From 4518c1ec21dd777f408e1992eb9943a11ffab1d3 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Fri, 1 Mar 2024 16:40:39 -0800 Subject: [PATCH] Reduce memory/cache overhead from over loader processing #62005 --- packages/next/src/build/webpack-config.ts | 3 +- .../build/webpack/loaders/next-swc-loader.ts | 45 +++++++++++++++++++ .../terser-webpack-plugin/src/index.ts | 10 ----- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index 4c0b906cc50cb..de209961f1a1d 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -103,7 +103,7 @@ if (parseInt(React.version) < 18) { throw new Error('Next.js requires react >= 18.2.0 to be installed.') } -const babelIncludeRegexes: RegExp[] = [ +export const babelIncludeRegexes: RegExp[] = [ /next[\\/]dist[\\/](esm[\\/])?shared[\\/]lib/, /next[\\/]dist[\\/](esm[\\/])?client/, /next[\\/]dist[\\/](esm[\\/])?pages/, @@ -455,6 +455,7 @@ export default async function getBaseWebpackConfig( jsConfig, supportedBrowsers, swcCacheDir: path.join(dir, config?.distDir ?? '.next', 'cache', 'swc'), + transpilePackages: config.transpilePackages, ...extraOptions, } satisfies SWCLoaderOptions, } diff --git a/packages/next/src/build/webpack/loaders/next-swc-loader.ts b/packages/next/src/build/webpack/loaders/next-swc-loader.ts index b1650fa4b8334..6ca51b575dcd0 100644 --- a/packages/next/src/build/webpack/loaders/next-swc-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-swc-loader.ts @@ -31,6 +31,22 @@ import type { WebpackLayerName } from '../../../lib/constants' import { isWasm, transform } from '../../swc' import { getLoaderSWCOptions } from '../../swc/options' import path, { isAbsolute } from 'path' +import { babelIncludeRegexes } from '../../webpack-config' +import { isResourceInPackages } from '../../handle-externals' + +const maybeExclude = ( + excludePath: string, + transpilePackages: string[] +): boolean => { + if (babelIncludeRegexes.some((r) => r.test(excludePath))) { + return false + } + + const shouldBeBundled = isResourceInPackages(excludePath, transpilePackages) + if (shouldBeBundled) return false + + return excludePath.includes('node_modules') +} export interface SWCLoaderOptions { rootDir: string @@ -46,8 +62,14 @@ export interface SWCLoaderOptions { serverComponents?: boolean bundleLayer?: WebpackLayerName esm?: boolean + transpilePackages?: string[] } +// these are exact code conditions checked +// for to force transpiling a `node_module` +const FORCE_TRANSPILE_CONDITIONS = + /(next\/font|next\/dynamic|use server|use client)/ + async function loaderTransform( this: any, parentTrace: any, @@ -58,6 +80,20 @@ async function loaderTransform( const filename = this.resourcePath let loaderOptions: SWCLoaderOptions = this.getOptions() || {} + const shouldMaybeExclude = maybeExclude( + filename, + loaderOptions.transpilePackages || [] + ) + + if (shouldMaybeExclude) { + if (!source) { + throw new Error(`Invariant might be excluded but missing source`) + } + + if (!FORCE_TRANSPILE_CONDITIONS.test(source)) { + return [source, inputSourceMap] + } + } const { isServer, @@ -150,8 +186,17 @@ const EXCLUDED_PATHS = export function pitch(this: any) { const callback = this.async() + let loaderOptions: SWCLoaderOptions = this.getOptions() || {} + + const shouldMaybeExclude = maybeExclude( + this.resourcePath, + loaderOptions.transpilePackages || [] + ) + ;(async () => { if ( + // if it might be excluded/no-op we can't use pitch loader + !shouldMaybeExclude && // TODO: investigate swc file reading in PnP mode? !process.versions.pnp && !EXCLUDED_PATHS.test(this.resourcePath) && diff --git a/packages/next/src/build/webpack/plugins/terser-webpack-plugin/src/index.ts b/packages/next/src/build/webpack/plugins/terser-webpack-plugin/src/index.ts index 5112b9cc503e7..96f847c2a94c4 100644 --- a/packages/next/src/build/webpack/plugins/terser-webpack-plugin/src/index.ts +++ b/packages/next/src/build/webpack/plugins/terser-webpack-plugin/src/index.ts @@ -98,16 +98,6 @@ export class TerserPlugin { return false } - // don't minify _middleware as it can break in some cases - // and doesn't provide too much of a benefit as it's server-side - if ( - name.match( - /(edge-runtime-webpack\.js|edge-chunks|middleware\.js$)/ - ) - ) { - return false - } - const { info } = res // Skip double minimize assets from child compilation