diff --git a/server/build/plugins/combine-assets-plugin.js b/server/build/plugins/combine-assets-plugin.js index e5655914e3c6f9be0fe2531d22eb374a3331f7e0..5093b051ed05e3b7bcc44b7e3ae92beb3c3f55da 100644 --- a/server/build/plugins/combine-assets-plugin.js +++ b/server/build/plugins/combine-assets-plugin.js @@ -1,5 +1,3 @@ -import { ConcatSource } from 'webpack-sources' - // This plugin combines a set of assets into a single asset // This should be only used with text assets, // otherwise the result is unpredictable. @@ -10,23 +8,23 @@ export default class CombineAssetsPlugin { } apply (compiler) { - compiler.plugin('compilation', (compilation) => { - compilation.plugin('optimize-chunk-assets', (chunks, callback) => { - const concat = new ConcatSource() - - this.input.forEach((name) => { - const asset = compilation.assets[name] - if (!asset) return + compiler.plugin('after-compile', (compilation, callback) => { + let newSource = '' + this.input.forEach((name) => { + const asset = compilation.assets[name] + if (!asset) return - concat.add(asset) + newSource += `${asset.source()}\n` - // We keep existing assets since that helps when analyzing the bundle - }) + // We keep existing assets since that helps when analyzing the bundle + }) - compilation.assets[this.output] = concat + compilation.assets[this.output] = { + source: () => newSource, + size: () => newSource.length + } - callback() - }) + callback() }) } } diff --git a/server/build/plugins/dynamic-chunks-plugin.js b/server/build/plugins/dynamic-chunks-plugin.js index 5e88528e30543179fb4af0d21f49ef31813d159a..8f00a9563511eb363ed0ae0b64cbab87460452df 100644 --- a/server/build/plugins/dynamic-chunks-plugin.js +++ b/server/build/plugins/dynamic-chunks-plugin.js @@ -1,37 +1,39 @@ -import { ConcatSource } from 'webpack-sources' - -export default class DynamicChunksPlugin { +export default class PagesPlugin { apply (compiler) { const isImportChunk = /^chunks[/\\].*\.js$/ const matchChunkName = /^chunks[/\\](.*)$/ - compiler.plugin('compilation', (compilation) => { - compilation.plugin('optimize-chunk-assets', (chunks, callback) => { - chunks = chunks.filter(chunk => isImportChunk.test(chunk.name)) - - chunks.forEach((chunk) => { - const asset = compilation.assets[chunk.name] - if (!asset) return - - const chunkName = matchChunkName.exec(chunk.name)[1] - const concat = new ConcatSource() - - concat.add(`__NEXT_REGISTER_CHUNK('${chunkName}', function() { - `) - concat.add(asset) - concat.add(` - }) - `) - - // Replace the exisiting chunk with the new content - compilation.assets[chunk.name] = concat - - // This is to support, webpack dynamic import support with HMR - compilation.assets[`chunks/${chunk.name}`] = concat - }) - - callback() + compiler.plugin('after-compile', (compilation, callback) => { + const chunks = Object + .keys(compilation.namedChunks) + .map(key => compilation.namedChunks[key]) + .filter(chunk => isImportChunk.test(chunk.name)) + + chunks.forEach((chunk) => { + const asset = compilation.assets[chunk.name] + if (!asset) return + + const chunkName = matchChunkName.exec(chunk.name)[1] + + const content = asset.source() + const newContent = ` + window.__NEXT_REGISTER_CHUNK('${chunkName}', function() { + ${content} + }) + ` + // Replace the exisiting chunk with the new content + compilation.assets[chunk.name] = { + source: () => newContent, + size: () => newContent.length + } + + // This is to support, webpack dynamic import support with HMR + compilation.assets[`chunks/${chunk.id}`] = { + source: () => newContent, + size: () => newContent.length + } }) + callback() }) } } diff --git a/server/build/plugins/pages-plugin.js b/server/build/plugins/pages-plugin.js index af149a4ec360c102d5bd820a899dd3298f8eec35..907630e6a825fecb69d7a50e86ba28f0ff5ce05e 100644 --- a/server/build/plugins/pages-plugin.js +++ b/server/build/plugins/pages-plugin.js @@ -1,4 +1,3 @@ -import { ConcatSource } from 'webpack-sources' import { IS_BUNDLED_PAGE, MATCH_ROUTE_NAME @@ -6,48 +5,43 @@ import { export default class PagesPlugin { apply (compiler) { - compiler.plugin('compilation', (compilation) => { - compilation.plugin('optimize-chunk-assets', (chunks, callback) => { - const pages = chunks.filter(chunk => IS_BUNDLED_PAGE.test(chunk.name)) - - pages.forEach((chunk) => { - const pageName = MATCH_ROUTE_NAME.exec(chunk.name)[1] - let routeName = pageName - - // We need to convert \ into / when we are in windows - // to get the proper route name - // Here we need to do windows check because it's possible - // to have "\" in the filename in unix. - // Anyway if someone did that, he'll be having issues here. - // But that's something we cannot avoid. - if (/^win/.test(process.platform)) { - routeName = routeName.replace(/\\/g, '/') - } - - routeName = `/${routeName.replace(/(^|\/)index$/, '')}` - - // Replace the exisiting chunk with the new content - const asset = compilation.assets[chunk.name] - if (!asset) return - - const concat = new ConcatSource() - - concat.add(` - __NEXT_REGISTER_PAGE('${routeName}', function() { - var comp = - `) - concat.add(asset) - concat.add(` - return { page: comp.default } - }) - `) - - // Replace the exisiting chunk with the new content - compilation.assets[chunk.name] = concat - }) - - callback() + compiler.plugin('after-compile', (compilation, callback) => { + const pages = Object + .keys(compilation.namedChunks) + .map(key => compilation.namedChunks[key]) + .filter(chunk => IS_BUNDLED_PAGE.test(chunk.name)) + + pages.forEach((chunk) => { + const page = compilation.assets[chunk.name] + const pageName = MATCH_ROUTE_NAME.exec(chunk.name)[1] + let routeName = pageName + + // We need to convert \ into / when we are in windows + // to get the proper route name + // Here we need to do windows check because it's possible + // to have "\" in the filename in unix. + // Anyway if someone did that, he'll be having issues here. + // But that's something we cannot avoid. + if (/^win/.test(process.platform)) { + routeName = routeName.replace(/\\/g, '/') + } + + routeName = `/${routeName.replace(/(^|\/)index$/, '')}` + + const content = page.source() + const newContent = ` + window.__NEXT_REGISTER_PAGE('${routeName}', function() { + var comp = ${content} + return { page: comp.default } + }) + ` + // Replace the exisiting chunk with the new content + compilation.assets[chunk.name] = { + source: () => newContent, + size: () => newContent.length + } }) + callback() }) } } diff --git a/server/index.js b/server/index.js index 164e6e38a8887cbf8f5e076f87ce916cd9089884..51a4b851d1254e4d985f0b39ea2ee3af1426877f 100644 --- a/server/index.js +++ b/server/index.js @@ -408,11 +408,7 @@ export default class Server { } handleBuildId (buildId, res) { - if (this.dev) { - res.setHeader('Cache-Control', 'no-store, must-revalidate') - return true - } - + if (this.dev) return true if (buildId !== this.renderOpts.buildId) { return false } @@ -432,17 +428,13 @@ export default class Server { } handleBuildHash (filename, hash, res) { - if (this.dev) { - res.setHeader('Cache-Control', 'no-store, must-revalidate') - return true - } + if (this.dev) return if (hash !== this.buildStats[filename].hash) { throw new Error(`Invalid Build File Hash(${hash}) for chunk: ${filename}`) } res.setHeader('Cache-Control', 'max-age=365000000, immutable') - return true } send404 (res) { diff --git a/server/render.js b/server/render.js index 77a8a1f8801728f890b397f5ca116ff8fbe2b521..0bb99ab84adc39c262515a287ce923de747ffeac 100644 --- a/server/render.js +++ b/server/render.js @@ -93,6 +93,11 @@ async function doRender (req, res, pathname, query, { } const docProps = await loadGetInitialProps(Document, { ...ctx, renderPage }) + // While developing, we should not cache any assets. + // So, we use a different buildId for each page load. + // With that we can ensure, we have unique URL for assets per every page load. + // So, it'll prevent issues like this: https://git.io/vHLtb + const devBuildId = Date.now() if (res.finished) return @@ -102,7 +107,7 @@ async function doRender (req, res, pathname, query, { props, pathname, query, - buildId, + buildId: dev ? devBuildId : buildId, buildStats, assetPrefix, nextExport,