Skip to content

Commit

Permalink
Update webpack server chunks output (#22697)
Browse files Browse the repository at this point in the history
This updates to output server chunks to a nested folder to prevent bundling the entire folder when tracing. This also fixes the webpack 5 tests not actually using webpack 5 since #22583 since the webpack 5 enabling check didn't account for the test environment variable used to enable webpack 5. This also clears up some deprecation warnings from webpack 5 in the mini-css-extract-plugin.

Fixes: #21297
  • Loading branch information
ijjk committed Mar 3, 2021
1 parent ac47795 commit b80fdfb
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 20 deletions.
22 changes: 16 additions & 6 deletions packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,7 @@ export default async function getBaseWebpackConfig(
splitChunks: isServer ? false : splitChunksConfig,
runtimeChunk: isServer
? isWebpack5 && !isLikeServerless
? { name: 'webpack-runtime' }
? { name: `${dev ? '' : 'chunks/'}webpack-runtime` }
: undefined
: { name: CLIENT_STATIC_FILES_RUNTIME_WEBPACK },
minimize: !(dev || isServer),
Expand Down Expand Up @@ -856,10 +856,15 @@ export default async function getBaseWebpackConfig(
},
}
: {}),
path: outputPath,
path:
isServer && isWebpack5 && !dev
? path.join(outputPath, 'chunks')
: outputPath,
// On the server we don't use the chunkhash
filename: isServer
? '[name].js'
? isWebpack5 && !dev
? '../[name].js'
: '[name].js'
: `static/chunks/[name]${dev ? '' : '-[chunkhash]'}.js`,
library: isServer ? undefined : '_N_E',
libraryTarget: isServer ? 'commonjs2' : 'assign',
Expand Down Expand Up @@ -1117,7 +1122,8 @@ export default async function getBaseWebpackConfig(
contextRegExp: /(next-server|next)[\\/]dist[\\/]/,
}),
isServerless && isServer && new ServerlessPlugin(),
isServer && new PagesManifestPlugin(isLikeServerless),
isServer &&
new PagesManifestPlugin({ serverless: isLikeServerless, dev }),
!isWebpack5 &&
target === 'server' &&
isServer &&
Expand All @@ -1141,8 +1147,12 @@ export default async function getBaseWebpackConfig(
(function () {
const {
FontStylesheetGatheringPlugin,
} = require('./webpack/plugins/font-stylesheet-gathering-plugin')
return new FontStylesheetGatheringPlugin()
} = require('./webpack/plugins/font-stylesheet-gathering-plugin') as {
FontStylesheetGatheringPlugin: typeof import('./webpack/plugins/font-stylesheet-gathering-plugin').FontStylesheetGatheringPlugin
}
return new FontStylesheetGatheringPlugin({
isLikeServerless,
})
})(),
config.experimental.conformance &&
!isWebpack5 &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ export class FontStylesheetGatheringPlugin {
compiler?: webpack.Compiler
gatheredStylesheets: Array<string> = []
manifestContent: FontManifest = []
isLikeServerless: boolean

constructor({ isLikeServerless }: { isLikeServerless: boolean }) {
this.isLikeServerless = isLikeServerless
}

private parserHandler = (
factory: webpack.compilation.NormalModuleFactory
Expand Down Expand Up @@ -137,8 +142,7 @@ export class FontStylesheetGatheringPlugin {
this.parserHandler
)
compiler.hooks.make.tapAsync(this.constructor.name, (compilation, cb) => {
// @ts-ignore
if (compilation.options.output.path.endsWith('serverless')) {
if (this.isLikeServerless) {
/**
* Inline font manifest for serverless case only.
* For target: server drive the manifest through physical file and less of webpack magic.
Expand Down Expand Up @@ -196,7 +200,7 @@ export class FontStylesheetGatheringPlugin {
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,
},
(assets: any) => {
assets[FONT_MANIFEST] = new sources.RawSource(
assets['../' + FONT_MANIFEST] = new sources.RawSource(
JSON.stringify(this.manifestContent, null, ' ')
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,13 +219,30 @@ class MiniCssExtractPlugin {

if (Object.keys(chunkMap).length > 0) {
const chunkMaps = chunk.getChunkMaps()
const { crossOriginLoading } = mainTemplate.outputOptions
const linkHrefPath = mainTemplate.getAssetPath(
const { crossOriginLoading } = isWebpack5
? compilation.outputOptions
: mainTemplate.outputOptions

const getHash = !isWebpack5
? (...args) => mainTemplate.renderCurrentHashCode(...args)
: (curHash, length) => {
if (length) {
return `${webpack.RuntimeGlobals.getFullHash} ? ${
webpack.RuntimeGlobals.getFullHash
}().slice(0, ${length}) : ${curHash.slice(0, length)}`
}
return `${webpack.RuntimeGlobals.getFullHash} ? ${webpack.RuntimeGlobals.getFullHash}() : ${curHash}`
}

const getAssetPath = isWebpack5
? (...args) => compilation.getAssetPath(...args)
: (...args) => mainTemplate.getAssetPath(...args)

const linkHrefPath = getAssetPath(
JSON.stringify(this.options.chunkFilename),
{
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
hashWithLength: (length) =>
`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
hash: `" + ${getHash(hash)} + "`,
hashWithLength: (length) => `" + ${getHash(hash, length)} + "`,
chunk: {
id: '" + chunkId + "',
hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,
Expand Down Expand Up @@ -286,7 +303,9 @@ class MiniCssExtractPlugin {
'promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {',
Template.indent([
`var href = ${linkHrefPath};`,
`var fullhref = ${mainTemplate.requireFn}.p + href;`,
`var fullhref = ${
isWebpack5 ? '__webpack_require__' : mainTemplate.requireFn
}.p + href;`,
'var existingLinkTags = document.getElementsByTagName("link");',
'for(var i = 0; i < existingLinkTags.length; i++) {',
Template.indent([
Expand Down
17 changes: 12 additions & 5 deletions packages/next/build/webpack/plugins/pages-manifest-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ export type PagesManifest = { [page: string]: string }
// It's also used by next export to provide defaultPathMap
export default class PagesManifestPlugin implements webpack.Plugin {
serverless: boolean
dev: boolean

constructor(serverless: boolean) {
constructor({ serverless, dev }: { serverless: boolean; dev: boolean }) {
this.serverless = serverless
this.dev = dev
}

createAssets(compilation: any, assets: any) {
Expand Down Expand Up @@ -45,12 +47,17 @@ export default class PagesManifestPlugin implements webpack.Plugin {
}

// Write filename, replace any backslashes in path (on windows) with forwardslashes for cross-platform consistency.
pages[pagePath] = files[0].replace(/\\/g, '/')
pages[pagePath] = files[0]

if (isWebpack5 && !this.dev) {
pages[pagePath] = pages[pagePath].slice(3)
}
pages[pagePath] = pages[pagePath].replace(/\\/g, '/')
}

assets[PAGES_MANIFEST] = new sources.RawSource(
JSON.stringify(pages, null, 2)
)
assets[
`${isWebpack5 && !this.dev ? '../' : ''}` + PAGES_MANIFEST
] = new sources.RawSource(JSON.stringify(pages, null, 2))
}

apply(compiler: webpack.Compiler): void {
Expand Down
4 changes: 4 additions & 0 deletions packages/next/next-server/server/config-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export async function shouldLoadWithWebpack5(
cwd: dir,
})

if (Number(process.env.NEXT_PRIVATE_TEST_WEBPACK5_MODE) > 0) {
return true
}

// No `next.config.js`:
if (!path?.length) {
return false // TODO: return true to default to webpack 5
Expand Down

0 comments on commit b80fdfb

Please sign in to comment.