diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 3718be6d5222..29c6985d1af0 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -19,7 +19,7 @@ import { getTypeScriptConfiguration } from '../lib/typescript/getTypeScriptConfi import { CLIENT_STATIC_FILES_RUNTIME_AMP, CLIENT_STATIC_FILES_RUNTIME_MAIN, - CLIENT_STATIC_FILES_RUNTIME_POLYFILLS, + CLIENT_STATIC_FILES_RUNTIME_POLYFILLS_SYMBOL, CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH, CLIENT_STATIC_FILES_RUNTIME_WEBPACK, REACT_LOADABLE_MANIFEST, @@ -52,6 +52,7 @@ import WebpackConformancePlugin, { } from './webpack/plugins/webpack-conformance-plugin' import { WellKnownErrorsPlugin } from './webpack/plugins/wellknown-errors-plugin' import { regexLikeCss } from './webpack/config/blocks/css' +import { CopyFilePlugin } from './webpack/plugins/copy-file-plugin' type ExcludesFalse = (x: T | false) => x is T @@ -364,10 +365,6 @@ export default async function getBaseWebpackConfig( ) ) .replace(/\\/g, '/'), - [CLIENT_STATIC_FILES_RUNTIME_POLYFILLS]: path.join( - NEXT_PROJECT_ROOT_DIST_CLIENT, - 'polyfills.js' - ), } as ClientEntries) : undefined @@ -1324,6 +1321,13 @@ export default async function getBaseWebpackConfig( ].filter(Boolean), }), new WellKnownErrorsPlugin(), + !isServer && + new CopyFilePlugin({ + source: require.resolve('./polyfills/polyfill-nomodule'), + name: `static/chunks/polyfills${dev ? '' : '-[hash]'}.js`, + minimize: false, + info: { [CLIENT_STATIC_FILES_RUNTIME_POLYFILLS_SYMBOL]: 1 }, + }), ].filter((Boolean as any) as ExcludesFalse), } diff --git a/packages/next/build/webpack/plugins/build-manifest-plugin.ts b/packages/next/build/webpack/plugins/build-manifest-plugin.ts index 2f5cb4d23f62..a6aa31c6c66a 100644 --- a/packages/next/build/webpack/plugins/build-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/build-manifest-plugin.ts @@ -8,7 +8,7 @@ import { BUILD_MANIFEST, CLIENT_STATIC_FILES_PATH, CLIENT_STATIC_FILES_RUNTIME_MAIN, - CLIENT_STATIC_FILES_RUNTIME_POLYFILLS, + CLIENT_STATIC_FILES_RUNTIME_POLYFILLS_SYMBOL, CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH, CLIENT_STATIC_FILES_RUNTIME_AMP, } from '../../../shared/lib/constants' @@ -146,9 +146,24 @@ export default class BuildManifestPlugin { getEntrypointFiles(entrypoints.get(CLIENT_STATIC_FILES_RUNTIME_MAIN)) ) - assetMap.polyfillFiles = getEntrypointFiles( - entrypoints.get(CLIENT_STATIC_FILES_RUNTIME_POLYFILLS) - ).filter((file) => !mainFiles.has(file)) + const compilationAssets: { + name: string + source: typeof sources.RawSource + info: object + }[] = compilation.getAssets() + + assetMap.polyfillFiles = compilationAssets + .filter((p) => { + // Ensure only .js files are passed through + if (!p.name.endsWith('.js')) { + return false + } + + return ( + p.info && CLIENT_STATIC_FILES_RUNTIME_POLYFILLS_SYMBOL in p.info + ) + }) + .map((v) => v.name) assetMap.devFiles = getEntrypointFiles( entrypoints.get(CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH) @@ -160,7 +175,6 @@ export default class BuildManifestPlugin { const systemEntrypoints = new Set([ CLIENT_STATIC_FILES_RUNTIME_MAIN, - CLIENT_STATIC_FILES_RUNTIME_POLYFILLS, CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH, CLIENT_STATIC_FILES_RUNTIME_AMP, ]) diff --git a/packages/next/build/webpack/plugins/copy-file-plugin.ts b/packages/next/build/webpack/plugins/copy-file-plugin.ts new file mode 100644 index 000000000000..185bc3d294fd --- /dev/null +++ b/packages/next/build/webpack/plugins/copy-file-plugin.ts @@ -0,0 +1,65 @@ +import { promises as fs } from 'fs' +import loaderUtils from 'next/dist/compiled/loader-utils' +import { + isWebpack5, + sources, + webpack, +} from 'next/dist/compiled/webpack/webpack' + +const PLUGIN_NAME = 'CopyFilePlugin' + +export class CopyFilePlugin { + private source: string + private name: string + private minimize: boolean + private info?: object + + constructor({ + source, + name, + minimize, + info, + }: { + source: string + name: string + minimize: boolean + info?: object + }) { + this.source = source + this.name = name + this.minimize = minimize + this.info = info + } + + apply(compiler: webpack.Compiler) { + compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => { + const hook = isWebpack5 + ? // @ts-ignore + compilation.hooks.processAssets + : compilation.hooks.additionalAssets + hook.tapPromise( + isWebpack5 + ? { + name: PLUGIN_NAME, + // @ts-ignore TODO: Remove ignore when webpack 5 is stable + stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS, + } + : PLUGIN_NAME, + async () => { + const content = await fs.readFile(this.source, 'utf8') + + const file = loaderUtils.interpolateName( + { resourcePath: this.source }, + this.name, + { content, context: compiler.context } + ) + + // @ts-ignore + compilation.emitAsset(file, new sources.RawSource(content), { + ...this.info, + }) + } + ) + }) + } +} diff --git a/packages/next/client/polyfills.js b/packages/next/client/polyfills.js deleted file mode 100644 index 6b8b07f69263..000000000000 --- a/packages/next/client/polyfills.js +++ /dev/null @@ -1 +0,0 @@ -import 'next/dist/build/polyfills/polyfill-nomodule' diff --git a/packages/next/shared/lib/constants.ts b/packages/next/shared/lib/constants.ts index 8ea2a7d271dd..d7d028a6bbfb 100644 --- a/packages/next/shared/lib/constants.ts +++ b/packages/next/shared/lib/constants.ts @@ -32,7 +32,7 @@ export const CLIENT_STATIC_FILES_RUNTIME_AMP = `amp` // static/runtime/webpack.js export const CLIENT_STATIC_FILES_RUNTIME_WEBPACK = `webpack` // static/runtime/polyfills.js -export const CLIENT_STATIC_FILES_RUNTIME_POLYFILLS = `polyfills` +export const CLIENT_STATIC_FILES_RUNTIME_POLYFILLS_SYMBOL = Symbol(`polyfills`) export const TEMPORARY_REDIRECT_STATUS = 307 export const PERMANENT_REDIRECT_STATUS = 308 export const STATIC_PROPS_ID = '__N_SSG'