From 89437a04dce84f7034a8606c7f3d94bf3e9bf138 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Thu, 21 Jan 2021 08:24:10 -0500 Subject: [PATCH 1/2] refactor: polyfill-nomodule handling This commit removes unnecessary redirection that bundles `@next/polyfill-nomodule`, which is a first-party dependency. --- packages/next/client/polyfills.js | 2 +- packages/next/package.json | 2 +- packages/next/taskfile.js | 15 +-------------- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/packages/next/client/polyfills.js b/packages/next/client/polyfills.js index 6b8b07f69263..5682d2a0577a 100644 --- a/packages/next/client/polyfills.js +++ b/packages/next/client/polyfills.js @@ -1 +1 @@ -import 'next/dist/build/polyfills/polyfill-nomodule' +import '@next/polyfill-nomodule' diff --git a/packages/next/package.json b/packages/next/package.json index d2da70eadcce..ba2c08e89a1f 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -65,6 +65,7 @@ "@hapi/accept": "5.0.1", "@next/env": "10.0.6-canary.6", "@next/polyfill-module": "10.0.6-canary.6", + "@next/polyfill-nomodule": "10.0.6-canary.6", "@next/react-dev-overlay": "10.0.6-canary.6", "@next/react-refresh-utils": "10.0.6-canary.6", "@opentelemetry/api": "0.14.0", @@ -135,7 +136,6 @@ "@babel/preset-react": "7.12.10", "@babel/preset-typescript": "7.12.7", "@babel/types": "7.12.12", - "@next/polyfill-nomodule": "10.0.6-canary.6", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", "@taskr/watch": "1.1.0", diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index a75a9cb0c85f..e7beb94ed5ac 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -19,19 +19,6 @@ const bundleRequire = m.require bundleRequire.resolve = (request, options) => Module._resolveFilename(request, m, false, options) -export async function next__polyfill_nomodule(task, opts) { - await task - .source( - opts.src || - relative(__dirname, require.resolve('@next/polyfill-nomodule')) - ) - .target('dist/build/polyfills') -} - -export async function browser_polyfills(task) { - await task.parallel(['next__polyfill_nomodule']) -} - const externals = { // Browserslist (post-css plugins) browserslist: 'browserslist', @@ -656,7 +643,7 @@ export async function path_to_regexp(task, opts) { } export async function precompile(task) { - await task.parallel(['browser_polyfills', 'path_to_regexp', 'copy_ncced']) + await task.parallel(['path_to_regexp', 'copy_ncced']) } // eslint-disable-next-line camelcase From f4273bb998875f327a5131bc7f191a7dbb995b49 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Thu, 21 Jan 2021 23:10:36 -0500 Subject: [PATCH 2/2] Add polyfills via a plugin --- packages/next/build/webpack-config.ts | 30 ++++---- .../webpack/plugins/build-manifest-plugin.ts | 35 ++++++---- .../build/webpack/plugins/copy-file-plugin.ts | 68 +++++++++++++++++++ packages/next/client/polyfills.js | 1 - packages/next/next-server/lib/constants.ts | 2 +- 5 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 packages/next/build/webpack/plugins/copy-file-plugin.ts delete mode 100644 packages/next/client/polyfills.js diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 2ea65df28332..0ddd92b68029 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1,17 +1,15 @@ -import { codeFrameColumns } from 'next/dist/compiled/babel/code-frame' import ReactRefreshWebpackPlugin from '@next/react-refresh-utils/ReactRefreshWebpackPlugin' +import chalk from 'chalk' import crypto from 'crypto' import { readFileSync, realpathSync } from 'fs' -import chalk from 'chalk' +import { codeFrameColumns } from 'next/dist/compiled/babel/code-frame' import semver from 'next/dist/compiled/semver' -// @ts-ignore No typings yet -import TerserPlugin from './webpack/plugins/terser-webpack-plugin/src/index.js' -import path from 'path' import { - webpack, - isWebpack5, init as initWebpack, + isWebpack5, + webpack, } from 'next/dist/compiled/webpack/webpack' +import path from 'path' import { DOT_NEXT_ALIAS, NEXT_PROJECT_ROOT, @@ -24,13 +22,14 @@ import { Rewrite } from '../lib/load-custom-routes' import { getTypeScriptConfiguration } from '../lib/typescript/getTypeScriptConfiguration' import { CLIENT_STATIC_FILES_RUNTIME_MAIN, - CLIENT_STATIC_FILES_RUNTIME_POLYFILLS, + CLIENT_STATIC_FILES_RUNTIME_POLYFILLS_SYMBOL, CLIENT_STATIC_FILES_RUNTIME_WEBPACK, REACT_LOADABLE_MANIFEST, SERVERLESS_DIRECTORY, SERVER_DIRECTORY, } from '../next-server/lib/constants' import { execOnce } from '../next-server/lib/utils' +import { NextConfig } from '../next-server/server/config' import { findPageFile } from '../server/lib/find-page-file' import { WebpackEntrypoints } from './entries' import * as Log from './output/log' @@ -44,6 +43,7 @@ import { __overrideCssConfiguration } from './webpack/config/blocks/css/override import { pluginLoaderOptions } from './webpack/loaders/next-plugin-loader' import BuildManifestPlugin from './webpack/plugins/build-manifest-plugin' import ChunkNamesPlugin from './webpack/plugins/chunk-names-plugin' +import { CopyFilePlugin } from './webpack/plugins/copy-file-plugin' import { CssMinimizerPlugin } from './webpack/plugins/css-minimizer-plugin' import { JsConfigPathsPlugin } from './webpack/plugins/jsconfig-paths-plugin' import { DropClientPage } from './webpack/plugins/next-drop-client-page-plugin' @@ -53,6 +53,8 @@ import PagesManifestPlugin from './webpack/plugins/pages-manifest-plugin' import { ProfilingPlugin } from './webpack/plugins/profiling-plugin' import { ReactLoadablePlugin } from './webpack/plugins/react-loadable-plugin' import { ServerlessPlugin } from './webpack/plugins/serverless-plugin' +// @ts-ignore No typings yet +import TerserPlugin from './webpack/plugins/terser-webpack-plugin/src/index.js' import WebpackConformancePlugin, { DuplicatePolyfillsConformanceCheck, GranularChunksConformanceCheck, @@ -60,7 +62,6 @@ import WebpackConformancePlugin, { ReactSyncScriptsConformanceCheck, } from './webpack/plugins/webpack-conformance-plugin' import { WellKnownErrorsPlugin } from './webpack/plugins/wellknown-errors-plugin' -import { NextConfig } from '../next-server/server/config' type ExcludesFalse = (x: T | false) => x is T @@ -298,10 +299,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 @@ -1149,6 +1146,13 @@ export default async function getBaseWebpackConfig( ].filter(Boolean), }), new WellKnownErrorsPlugin(), + !isServer && + new CopyFilePlugin({ + source: require.resolve('@next/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 5cfe31ba85d6..0074fb280b61 100644 --- a/packages/next/build/webpack/plugins/build-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/build-manifest-plugin.ts @@ -1,23 +1,23 @@ import devalue from 'next/dist/compiled/devalue' import { - webpack, isWebpack5, sources, + webpack, } from 'next/dist/compiled/webpack/webpack' +import { Rewrite } from '../../../lib/load-custom-routes' import { BUILD_MANIFEST, CLIENT_STATIC_FILES_PATH, + 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_AMP, } from '../../../next-server/lib/constants' +import { getSortedRoutes } from '../../../next-server/lib/router/utils' import { BuildManifest } from '../../../next-server/server/get-page-files' import getRouteFromEntrypoint from '../../../next-server/server/get-route-from-entrypoint' +import { traceFn, tracer } from '../../tracer' import { ampFirstEntryNamesMap } from './next-drop-client-page-plugin' -import { Rewrite } from '../../../lib/load-custom-routes' -import { getSortedRoutes } from '../../../next-server/lib/router/utils' -import { tracer, traceFn } from '../../tracer' import { spans } from './profiling-plugin' type DeepMutable = { -readonly [P in keyof T]: DeepMutable } @@ -117,6 +117,12 @@ export default class BuildManifestPlugin { ampFirstPages: [], } + const compilationAssets: { + name: string + source: typeof sources.RawSource + info: object + }[] = compilation.getAssets() + const ampFirstEntryNames = ampFirstEntryNamesMap.get(compilation) if (ampFirstEntryNames) { for (const entryName of ampFirstEntryNames) { @@ -135,14 +141,13 @@ export default class BuildManifestPlugin { isJsFile ) - const polyfillChunk = namedChunks.get( - CLIENT_STATIC_FILES_RUNTIME_POLYFILLS - ) - - // Create a separate entry for polyfills - assetMap.polyfillFiles = getFilesArray(polyfillChunk?.files).filter( - isJsFile - ) + assetMap.polyfillFiles = compilationAssets + .filter( + (p) => + p.info && CLIENT_STATIC_FILES_RUNTIME_POLYFILLS_SYMBOL in p.info + ) + .map((v) => v.name) + .filter(isJsFile) const reactRefreshChunk = namedChunks.get( CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH @@ -233,7 +238,7 @@ export default class BuildManifestPlugin { { name: 'NextJsBuildManifest', // @ts-ignore TODO: Remove ignore when webpack 5 is stable - stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS, + stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ANALYSE, }, (assets: any) => { this.createAssets(compiler, compilation, assets) 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..8a7684478475 --- /dev/null +++ b/packages/next/build/webpack/plugins/copy-file-plugin.ts @@ -0,0 +1,68 @@ +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, + stage: this.minimize + ? // @ts-ignore + webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL + : // @ts-ignore + webpack.Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING, + } + : 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 5682d2a0577a..000000000000 --- a/packages/next/client/polyfills.js +++ /dev/null @@ -1 +0,0 @@ -import '@next/polyfill-nomodule' diff --git a/packages/next/next-server/lib/constants.ts b/packages/next/next-server/lib/constants.ts index 03a4fc100705..5455f3fe7938 100644 --- a/packages/next/next-server/lib/constants.ts +++ b/packages/next/next-server/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'