From 964f229f982e979c1990065b6a40caeaefd3be41 Mon Sep 17 00:00:00 2001 From: Kevin Decker Date: Thu, 19 Oct 2017 15:11:37 -0500 Subject: [PATCH] Sourcemap and Breakpoint Fixes (#3121) * Propagate source maps through combine assets step * Use constant development build id --- server/build/plugins/combine-assets-plugin.js | 28 +++---- server/build/plugins/dynamic-chunks-plugin.js | 60 +++++++------- server/build/plugins/pages-plugin.js | 78 ++++++++++--------- server/index.js | 12 ++- server/render.js | 7 +- 5 files changed, 97 insertions(+), 88 deletions(-) diff --git a/server/build/plugins/combine-assets-plugin.js b/server/build/plugins/combine-assets-plugin.js index 5093b051ed..e5655914e3 100644 --- a/server/build/plugins/combine-assets-plugin.js +++ b/server/build/plugins/combine-assets-plugin.js @@ -1,3 +1,5 @@ +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. @@ -8,23 +10,23 @@ export default class CombineAssetsPlugin { } apply (compiler) { - compiler.plugin('after-compile', (compilation, callback) => { - let newSource = '' - this.input.forEach((name) => { - const asset = compilation.assets[name] - if (!asset) return + compiler.plugin('compilation', (compilation) => { + compilation.plugin('optimize-chunk-assets', (chunks, callback) => { + const concat = new ConcatSource() - newSource += `${asset.source()}\n` + this.input.forEach((name) => { + const asset = compilation.assets[name] + if (!asset) return - // We keep existing assets since that helps when analyzing the bundle - }) + concat.add(asset) - compilation.assets[this.output] = { - source: () => newSource, - size: () => newSource.length - } + // We keep existing assets since that helps when analyzing the bundle + }) - callback() + compilation.assets[this.output] = concat + + callback() + }) }) } } diff --git a/server/build/plugins/dynamic-chunks-plugin.js b/server/build/plugins/dynamic-chunks-plugin.js index 8f00a95635..5e88528e30 100644 --- a/server/build/plugins/dynamic-chunks-plugin.js +++ b/server/build/plugins/dynamic-chunks-plugin.js @@ -1,39 +1,37 @@ -export default class PagesPlugin { +import { ConcatSource } from 'webpack-sources' + +export default class DynamicChunksPlugin { apply (compiler) { const isImportChunk = /^chunks[/\\].*\.js$/ const matchChunkName = /^chunks[/\\](.*)$/ - 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 - } + 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() }) - callback() }) } } diff --git a/server/build/plugins/pages-plugin.js b/server/build/plugins/pages-plugin.js index 907630e6a8..af149a4ec3 100644 --- a/server/build/plugins/pages-plugin.js +++ b/server/build/plugins/pages-plugin.js @@ -1,3 +1,4 @@ +import { ConcatSource } from 'webpack-sources' import { IS_BUNDLED_PAGE, MATCH_ROUTE_NAME @@ -5,43 +6,48 @@ import { export default class PagesPlugin { apply (compiler) { - 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 - } + 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() }) - callback() }) } } diff --git a/server/index.js b/server/index.js index 51a4b851d1..164e6e38a8 100644 --- a/server/index.js +++ b/server/index.js @@ -408,7 +408,11 @@ export default class Server { } handleBuildId (buildId, res) { - if (this.dev) return true + if (this.dev) { + res.setHeader('Cache-Control', 'no-store, must-revalidate') + return true + } + if (buildId !== this.renderOpts.buildId) { return false } @@ -428,13 +432,17 @@ export default class Server { } handleBuildHash (filename, hash, res) { - if (this.dev) return + if (this.dev) { + res.setHeader('Cache-Control', 'no-store, must-revalidate') + return true + } 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 0bb99ab84a..77a8a1f880 100644 --- a/server/render.js +++ b/server/render.js @@ -93,11 +93,6 @@ 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 @@ -107,7 +102,7 @@ async function doRender (req, res, pathname, query, { props, pathname, query, - buildId: dev ? devBuildId : buildId, + buildId, buildStats, assetPrefix, nextExport, -- GitLab