next
Version:
The React Framework
975 lines (974 loc) • 117 kB
JavaScript
import React from "react";
import ReactRefreshWebpackPlugin from "next/dist/compiled/@next/react-refresh-utils/dist/ReactRefreshWebpackPlugin";
import chalk from "next/dist/compiled/chalk";
import crypto from "crypto";
import { webpack } from "next/dist/compiled/webpack/webpack";
import path from "path";
import semver from "next/dist/compiled/semver";
import { escapeStringRegexp } from "../shared/lib/escape-regexp";
import { DOT_NEXT_ALIAS, PAGES_DIR_ALIAS, ROOT_DIR_ALIAS, APP_DIR_ALIAS, WEBPACK_LAYERS, RSC_ACTION_PROXY_ALIAS, RSC_ACTION_CLIENT_WRAPPER_ALIAS, RSC_ACTION_VALIDATE_ALIAS, WEBPACK_RESOURCE_QUERIES } from "../lib/constants";
import { fileExists } from "../lib/file-exists";
import { isEdgeRuntime } from "../lib/is-edge-runtime";
import { CLIENT_STATIC_FILES_RUNTIME_AMP, CLIENT_STATIC_FILES_RUNTIME_MAIN, CLIENT_STATIC_FILES_RUNTIME_MAIN_APP, CLIENT_STATIC_FILES_RUNTIME_POLYFILLS_SYMBOL, CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH, CLIENT_STATIC_FILES_RUNTIME_WEBPACK, MIDDLEWARE_REACT_LOADABLE_MANIFEST, REACT_LOADABLE_MANIFEST, SERVER_DIRECTORY, COMPILER_NAMES } from "../shared/lib/constants";
import { execOnce } from "../shared/lib/utils";
import { finalizeEntrypoint } from "./entries";
import * as Log from "./output/log";
import { buildConfiguration } from "./webpack/config";
import MiddlewarePlugin, { getEdgePolyfilledModules, handleWebpackExternalForEdgeRuntime } from "./webpack/plugins/middleware-plugin";
import BuildManifestPlugin from "./webpack/plugins/build-manifest-plugin";
import { JsConfigPathsPlugin } from "./webpack/plugins/jsconfig-paths-plugin";
import { DropClientPage } from "./webpack/plugins/next-drop-client-page-plugin";
import PagesManifestPlugin from "./webpack/plugins/pages-manifest-plugin";
import { ProfilingPlugin } from "./webpack/plugins/profiling-plugin";
import { ReactLoadablePlugin } from "./webpack/plugins/react-loadable-plugin";
import { WellKnownErrorsPlugin } from "./webpack/plugins/wellknown-errors-plugin";
import { regexLikeCss } from "./webpack/config/blocks/css";
import { CopyFilePlugin } from "./webpack/plugins/copy-file-plugin";
import { ClientReferenceManifestPlugin } from "./webpack/plugins/flight-manifest-plugin";
import { FlightClientEntryPlugin } from "./webpack/plugins/flight-client-entry-plugin";
import { NextTypesPlugin } from "./webpack/plugins/next-types-plugin";
import loadJsConfig from "./load-jsconfig";
import { loadBindings } from "./swc";
import { AppBuildManifestPlugin } from "./webpack/plugins/app-build-manifest-plugin";
import { SubresourceIntegrityPlugin } from "./webpack/plugins/subresource-integrity-plugin";
import { NextFontManifestPlugin } from "./webpack/plugins/next-font-manifest-plugin";
import { getSupportedBrowsers } from "./utils";
const EXTERNAL_PACKAGES = require("../lib/server-external-packages.json");
const NEXT_PROJECT_ROOT = path.join(__dirname, "..", "..");
const NEXT_PROJECT_ROOT_DIST = path.join(NEXT_PROJECT_ROOT, "dist");
const NEXT_PROJECT_ROOT_DIST_CLIENT = path.join(NEXT_PROJECT_ROOT_DIST, "client");
const isWebpackServerLayer = (layer)=>Boolean(layer && WEBPACK_LAYERS.GROUP.server.includes(layer));
if (parseInt(React.version) < 18) {
throw new Error("Next.js requires react >= 18.2.0 to be installed.");
}
const babelIncludeRegexes = [
/next[\\/]dist[\\/](esm[\\/])?shared[\\/]lib/,
/next[\\/]dist[\\/](esm[\\/])?client/,
/next[\\/]dist[\\/](esm[\\/])?pages/,
/[\\/](strip-ansi|ansi-regex|styled-jsx)[\\/]/
];
const reactPackagesRegex = /^(react|react-dom|react-server-dom-webpack)($|\/)/;
const asyncStoragesRegex = /next[\\/]dist[\\/](esm[\\/])?client[\\/]components[\\/](static-generation-async-storage|action-async-storage|request-async-storage)/;
// exports.<conditionName>
const edgeConditionNames = [
"edge-light",
"worker",
// inherits the default conditions
"..."
];
// packageJson.<mainField>
const mainFieldsPerCompiler = {
[COMPILER_NAMES.server]: [
"main",
"module"
],
[COMPILER_NAMES.client]: [
"browser",
"module",
"main"
],
[COMPILER_NAMES.edgeServer]: [
"edge-light",
"worker",
// inherits the default conditions
"..."
]
};
const BABEL_CONFIG_FILES = [
".babelrc",
".babelrc.json",
".babelrc.js",
".babelrc.mjs",
".babelrc.cjs",
"babel.config.js",
"babel.config.json",
"babel.config.mjs",
"babel.config.cjs"
];
export const getBabelConfigFile = async (dir)=>{
const babelConfigFile = await BABEL_CONFIG_FILES.reduce(async (memo, filename)=>{
const configFilePath = path.join(dir, filename);
return await memo || (await fileExists(configFilePath) ? configFilePath : undefined);
}, Promise.resolve(undefined));
return babelConfigFile;
};
// Support for NODE_PATH
const nodePathList = (process.env.NODE_PATH || "").split(process.platform === "win32" ? ";" : ":").filter((p)=>!!p);
const watchOptions = Object.freeze({
aggregateTimeout: 5,
ignored: // Matches **/node_modules/**, **/.git/** and **/.next/**
/^((?:[^/]*(?:\/|$))*)(\.(git|next)|node_modules)(\/((?:[^/]*(?:\/|$))*)(?:$|\/))?/
});
function isModuleCSS(module) {
return(// mini-css-extract-plugin
module.type === `css/mini-extract` || // extract-css-chunks-webpack-plugin (old)
module.type === `css/extract-chunks` || // extract-css-chunks-webpack-plugin (new)
module.type === `css/extract-css-chunks`);
}
function errorIfEnvConflicted(config, key) {
const isPrivateKey = /^(?:NODE_.+)|^(?:__.+)$/i.test(key);
const hasNextRuntimeKey = key === "NEXT_RUNTIME";
if (isPrivateKey || hasNextRuntimeKey) {
throw new Error(`The key "${key}" under "env" in ${config.configFileName} is not allowed. https://nextjs.org/docs/messages/env-key-not-allowed`);
}
}
function isResourceInPackages(resource, packageNames, packageDirMapping) {
return packageNames == null ? void 0 : packageNames.some((p)=>packageDirMapping && packageDirMapping.has(p) ? resource.startsWith(packageDirMapping.get(p) + path.sep) : resource.includes(path.sep + path.join("node_modules", p.replace(/\//g, path.sep)) + path.sep));
}
export function getDefineEnv({ dev , config , distDir , isClient , hasRewrites , isNodeServer , isEdgeServer , middlewareMatchers , clientRouterFilters , previewModeId , fetchCacheKeyPrefix , allowedRevalidateHeaderKeys }) {
var _config_images, _config_images1, _config_i18n;
return {
// internal field to identify the plugin config
__NEXT_DEFINE_ENV: "true",
...Object.keys(process.env).reduce((prev, key)=>{
if (key.startsWith("NEXT_PUBLIC_")) {
prev[`process.env.${key}`] = JSON.stringify(process.env[key]);
}
return prev;
}, {}),
...Object.keys(config.env).reduce((acc, key)=>{
errorIfEnvConflicted(config, key);
return {
...acc,
[`process.env.${key}`]: JSON.stringify(config.env[key])
};
}, {}),
...!isEdgeServer ? {} : {
EdgeRuntime: JSON.stringify(/**
* Cloud providers can set this environment variable to allow users
* and library authors to have different implementations based on
* the runtime they are running with, if it's not using `edge-runtime`
*/ process.env.NEXT_EDGE_RUNTIME_PROVIDER || "edge-runtime")
},
"process.turbopack": JSON.stringify(false),
// TODO: enforce `NODE_ENV` on `process.env`, and add a test:
"process.env.NODE_ENV": JSON.stringify(dev ? "development" : "production"),
"process.env.NEXT_RUNTIME": JSON.stringify(isEdgeServer ? "edge" : isNodeServer ? "nodejs" : undefined),
"process.env.__NEXT_ACTIONS_DEPLOYMENT_ID": JSON.stringify(config.experimental.useDeploymentIdServerActions),
"process.env.NEXT_DEPLOYMENT_ID": JSON.stringify(config.experimental.deploymentId),
"process.env.__NEXT_FETCH_CACHE_KEY_PREFIX": JSON.stringify(fetchCacheKeyPrefix),
"process.env.__NEXT_PREVIEW_MODE_ID": JSON.stringify(previewModeId),
"process.env.__NEXT_ALLOWED_REVALIDATE_HEADERS": JSON.stringify(allowedRevalidateHeaderKeys),
"process.env.__NEXT_MIDDLEWARE_MATCHERS": JSON.stringify(middlewareMatchers || []),
"process.env.__NEXT_MANUAL_CLIENT_BASE_PATH": JSON.stringify(config.experimental.manualClientBasePath),
"process.env.__NEXT_NEW_LINK_BEHAVIOR": JSON.stringify(config.experimental.newNextLinkBehavior),
"process.env.__NEXT_CLIENT_ROUTER_FILTER_ENABLED": JSON.stringify(config.experimental.clientRouterFilter),
"process.env.__NEXT_CLIENT_ROUTER_S_FILTER": JSON.stringify(clientRouterFilters == null ? void 0 : clientRouterFilters.staticFilter),
"process.env.__NEXT_CLIENT_ROUTER_D_FILTER": JSON.stringify(clientRouterFilters == null ? void 0 : clientRouterFilters.dynamicFilter),
"process.env.__NEXT_OPTIMISTIC_CLIENT_CACHE": JSON.stringify(config.experimental.optimisticClientCache),
"process.env.__NEXT_MIDDLEWARE_PREFETCH": JSON.stringify(config.experimental.middlewarePrefetch),
"process.env.__NEXT_CROSS_ORIGIN": JSON.stringify(config.crossOrigin),
"process.browser": JSON.stringify(isClient),
"process.env.__NEXT_TEST_MODE": JSON.stringify(process.env.__NEXT_TEST_MODE),
// This is used in client/dev-error-overlay/hot-dev-client.js to replace the dist directory
...dev && (isClient || isEdgeServer) ? {
"process.env.__NEXT_DIST_DIR": JSON.stringify(distDir)
} : {},
"process.env.__NEXT_TRAILING_SLASH": JSON.stringify(config.trailingSlash),
"process.env.__NEXT_BUILD_INDICATOR": JSON.stringify(config.devIndicators.buildActivity),
"process.env.__NEXT_BUILD_INDICATOR_POSITION": JSON.stringify(config.devIndicators.buildActivityPosition),
"process.env.__NEXT_STRICT_MODE": JSON.stringify(config.reactStrictMode === null ? false : config.reactStrictMode),
"process.env.__NEXT_STRICT_MODE_APP": JSON.stringify(// When next.config.js does not have reactStrictMode enabling appDir will enable it.
config.reactStrictMode === null ? config.experimental.appDir ? true : false : config.reactStrictMode),
"process.env.__NEXT_OPTIMIZE_FONTS": JSON.stringify(!dev && config.optimizeFonts),
"process.env.__NEXT_OPTIMIZE_CSS": JSON.stringify(config.experimental.optimizeCss && !dev),
"process.env.__NEXT_SCRIPT_WORKERS": JSON.stringify(config.experimental.nextScriptWorkers && !dev),
"process.env.__NEXT_SCROLL_RESTORATION": JSON.stringify(config.experimental.scrollRestoration),
"process.env.__NEXT_IMAGE_OPTS": JSON.stringify({
deviceSizes: config.images.deviceSizes,
imageSizes: config.images.imageSizes,
path: config.images.path,
loader: config.images.loader,
dangerouslyAllowSVG: config.images.dangerouslyAllowSVG,
unoptimized: config == null ? void 0 : (_config_images = config.images) == null ? void 0 : _config_images.unoptimized,
...dev ? {
// pass domains in development to allow validating on the client
domains: config.images.domains,
remotePatterns: (_config_images1 = config.images) == null ? void 0 : _config_images1.remotePatterns,
output: config.output
} : {}
}),
"process.env.__NEXT_ROUTER_BASEPATH": JSON.stringify(config.basePath),
"process.env.__NEXT_STRICT_NEXT_HEAD": JSON.stringify(config.experimental.strictNextHead),
"process.env.__NEXT_HAS_REWRITES": JSON.stringify(hasRewrites),
"process.env.__NEXT_CONFIG_OUTPUT": JSON.stringify(config.output),
"process.env.__NEXT_I18N_SUPPORT": JSON.stringify(!!config.i18n),
"process.env.__NEXT_I18N_DOMAINS": JSON.stringify((_config_i18n = config.i18n) == null ? void 0 : _config_i18n.domains),
"process.env.__NEXT_ANALYTICS_ID": JSON.stringify(config.analyticsId),
"process.env.__NEXT_NO_MIDDLEWARE_URL_NORMALIZE": JSON.stringify(config.skipMiddlewareUrlNormalize),
"process.env.__NEXT_EXTERNAL_MIDDLEWARE_REWRITE_RESOLVE": JSON.stringify(config.experimental.externalMiddlewareRewritesResolve),
"process.env.__NEXT_MANUAL_TRAILING_SLASH": JSON.stringify(config.skipTrailingSlashRedirect),
"process.env.__NEXT_HAS_WEB_VITALS_ATTRIBUTION": JSON.stringify(config.experimental.webVitalsAttribution && config.experimental.webVitalsAttribution.length > 0),
"process.env.__NEXT_WEB_VITALS_ATTRIBUTION": JSON.stringify(config.experimental.webVitalsAttribution),
"process.env.__NEXT_ASSET_PREFIX": JSON.stringify(config.assetPrefix),
...isNodeServer || isEdgeServer ? {
// Fix bad-actors in the npm ecosystem (e.g. `node-formidable`)
// This is typically found in unmaintained modules from the
// pre-webpack era (common in server-side code)
"global.GENTLY": JSON.stringify(false)
} : undefined,
// stub process.env with proxy to warn a missing value is
// being accessed in development mode
...config.experimental.pageEnv && dev ? {
"process.env": `
new Proxy(${isNodeServer ? "process.env" : "{}"}, {
get(target, prop) {
if (typeof target[prop] === 'undefined') {
console.warn(\`An environment variable (\${prop}) that was not provided in the environment was accessed.\nSee more info here: https://nextjs.org/docs/messages/missing-env-value\`)
}
return target[prop]
}
})
`
} : {}
};
}
function getReactProfilingInProduction() {
return {
"react-dom$": "react-dom/profiling",
"scheduler/tracing": "scheduler/tracing-profiling"
};
}
function createRSCAliases(bundledReactChannel, opts) {
const alias = {
react$: `next/dist/compiled/react${bundledReactChannel}`,
"react-dom$": `next/dist/compiled/react-dom${bundledReactChannel}`,
"react/jsx-runtime$": `next/dist/compiled/react${bundledReactChannel}/jsx-runtime`,
"react/jsx-dev-runtime$": `next/dist/compiled/react${bundledReactChannel}/jsx-dev-runtime`,
"react-dom/client$": `next/dist/compiled/react-dom${bundledReactChannel}/client`,
"react-dom/server$": `next/dist/compiled/react-dom${bundledReactChannel}/server`,
"react-dom/server.edge$": `next/dist/compiled/react-dom${bundledReactChannel}/server.edge`,
"react-dom/server.browser$": `next/dist/compiled/react-dom${bundledReactChannel}/server.browser`,
"react-server-dom-webpack/client$": `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/client`,
"react-server-dom-webpack/client.edge$": `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/client.edge`,
"react-server-dom-webpack/server.edge$": `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/server.edge`,
"react-server-dom-webpack/server.node$": `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/server.node`
};
if (opts.reactSharedSubset) {
alias["react$"] = `next/dist/compiled/react${bundledReactChannel}/react.shared-subset`;
}
// Use server rendering stub for RSC
// x-ref: https://github.com/facebook/react/pull/25436
if (opts.reactDomServerRenderingStub) {
alias["react-dom$"] = `next/dist/compiled/react-dom${bundledReactChannel}/server-rendering-stub`;
}
// Alias `server-only` and `client-only` modules to their server/client only, vendored versions.
// These aliases are necessary if the user doesn't have those two packages installed manually.
if (typeof opts.reactServerCondition !== "undefined") {
if (opts.reactServerCondition) {
// Alias to the `react-server` exports.
alias["server-only$"] = "next/dist/compiled/server-only/empty";
alias["client-only$"] = "next/dist/compiled/client-only/error";
} else {
alias["server-only$"] = "next/dist/compiled/server-only/index";
alias["client-only$"] = "next/dist/compiled/client-only/index";
}
}
if (opts.reactProductionProfiling) {
alias["react-dom$"] = `next/dist/compiled/react-dom${bundledReactChannel}/profiling`;
alias["scheduler/tracing"] = `next/dist/compiled/scheduler${bundledReactChannel}/tracing-profiling`;
}
return alias;
}
const devtoolRevertWarning = execOnce((devtool)=>{
console.warn(chalk.yellow.bold("Warning: ") + chalk.bold(`Reverting webpack devtool to '${devtool}'.\n`) + "Changing the webpack devtool in development mode will cause severe performance regressions.\n" + "Read more: https://nextjs.org/docs/messages/improper-devtool");
});
let loggedSwcDisabled = false;
let loggedIgnoredCompilerOptions = false;
function getOptimizedAliases() {
const stubWindowFetch = path.join(__dirname, "polyfills", "fetch", "index.js");
const stubObjectAssign = path.join(__dirname, "polyfills", "object-assign.js");
const shimAssign = path.join(__dirname, "polyfills", "object.assign");
return Object.assign({}, {
unfetch$: stubWindowFetch,
"isomorphic-unfetch$": stubWindowFetch,
"whatwg-fetch$": path.join(__dirname, "polyfills", "fetch", "whatwg-fetch.js")
}, {
"object-assign$": stubObjectAssign,
// Stub Package: object.assign
"object.assign/auto": path.join(shimAssign, "auto.js"),
"object.assign/implementation": path.join(shimAssign, "implementation.js"),
"object.assign$": path.join(shimAssign, "index.js"),
"object.assign/polyfill": path.join(shimAssign, "polyfill.js"),
"object.assign/shim": path.join(shimAssign, "shim.js"),
// Replace: full URL polyfill with platform-based polyfill
url: require.resolve("next/dist/compiled/native-url")
});
}
export function attachReactRefresh(webpackConfig, targetLoader) {
var _webpackConfig_module, _webpackConfig_module_rules;
let injections = 0;
const reactRefreshLoaderName = "next/dist/compiled/@next/react-refresh-utils/dist/loader";
const reactRefreshLoader = require.resolve(reactRefreshLoaderName);
(_webpackConfig_module = webpackConfig.module) == null ? void 0 : (_webpackConfig_module_rules = _webpackConfig_module.rules) == null ? void 0 : _webpackConfig_module_rules.forEach((rule)=>{
if (rule && typeof rule === "object" && "use" in rule) {
const curr = rule.use;
// When the user has configured `defaultLoaders.babel` for a input file:
if (curr === targetLoader) {
++injections;
rule.use = [
reactRefreshLoader,
curr
];
} else if (Array.isArray(curr) && curr.some((r)=>r === targetLoader) && // Check if loader already exists:
!curr.some((r)=>r === reactRefreshLoader || r === reactRefreshLoaderName)) {
++injections;
const idx = curr.findIndex((r)=>r === targetLoader);
// Clone to not mutate user input
rule.use = [
...curr
];
// inject / input: [other, babel] output: [other, refresh, babel]:
rule.use.splice(idx, 0, reactRefreshLoader);
}
}
});
if (injections) {
Log.info(`automatically enabled Fast Refresh for ${injections} custom loader${injections > 1 ? "s" : ""}`);
}
}
export const NODE_RESOLVE_OPTIONS = {
dependencyType: "commonjs",
modules: [
"node_modules"
],
fallback: false,
exportsFields: [
"exports"
],
importsFields: [
"imports"
],
conditionNames: [
"node",
"require"
],
descriptionFiles: [
"package.json"
],
extensions: [
".js",
".json",
".node"
],
enforceExtensions: false,
symlinks: true,
mainFields: [
"main"
],
mainFiles: [
"index"
],
roots: [],
fullySpecified: false,
preferRelative: false,
preferAbsolute: false,
restrictions: []
};
export const NODE_BASE_RESOLVE_OPTIONS = {
...NODE_RESOLVE_OPTIONS,
alias: false
};
export const NODE_ESM_RESOLVE_OPTIONS = {
...NODE_RESOLVE_OPTIONS,
alias: false,
dependencyType: "esm",
conditionNames: [
"node",
"import"
],
fullySpecified: true
};
export const NODE_BASE_ESM_RESOLVE_OPTIONS = {
...NODE_ESM_RESOLVE_OPTIONS,
alias: false
};
export const nextImageLoaderRegex = /\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i;
export async function resolveExternal(dir, esmExternalsConfig, context, request, isEsmRequested, hasAppDir, getResolve, isLocalCallback, baseResolveCheck = true, esmResolveOptions = NODE_ESM_RESOLVE_OPTIONS, nodeResolveOptions = NODE_RESOLVE_OPTIONS, baseEsmResolveOptions = NODE_BASE_ESM_RESOLVE_OPTIONS, baseResolveOptions = NODE_BASE_RESOLVE_OPTIONS) {
const esmExternals = !!esmExternalsConfig;
const looseEsmExternals = esmExternalsConfig === "loose";
let res = null;
let isEsm = false;
let preferEsmOptions = esmExternals && isEsmRequested ? [
true,
false
] : [
false
];
// Disable esm resolving for app/ and pages/ so for esm package using under pages/
// won't load react through esm loader
if (hasAppDir) {
preferEsmOptions = [
false
];
}
for (const preferEsm of preferEsmOptions){
const resolve = getResolve(preferEsm ? esmResolveOptions : nodeResolveOptions);
// Resolve the import with the webpack provided context, this
// ensures we're resolving the correct version when multiple
// exist.
try {
[res, isEsm] = await resolve(context, request);
} catch (err) {
res = null;
}
if (!res) {
continue;
}
// ESM externals can only be imported (and not required).
// Make an exception in loose mode.
if (!isEsmRequested && isEsm && !looseEsmExternals) {
continue;
}
if (isLocalCallback) {
return {
localRes: isLocalCallback(res)
};
}
// Bundled Node.js code is relocated without its node_modules tree.
// This means we need to make sure its request resolves to the same
// package that'll be available at runtime. If it's not identical,
// we need to bundle the code (even if it _should_ be external).
if (baseResolveCheck) {
let baseRes;
let baseIsEsm;
try {
const baseResolve = getResolve(isEsm ? baseEsmResolveOptions : baseResolveOptions);
[baseRes, baseIsEsm] = await baseResolve(dir, request);
} catch (err) {
baseRes = null;
baseIsEsm = false;
}
// Same as above: if the package, when required from the root,
// would be different from what the real resolution would use, we
// cannot externalize it.
// if request is pointing to a symlink it could point to the the same file,
// the resolver will resolve symlinks so this is handled
if (baseRes !== res || isEsm !== baseIsEsm) {
res = null;
continue;
}
}
break;
}
return {
res,
isEsm
};
}
export async function loadProjectInfo({ dir , config , dev }) {
const { jsConfig , resolvedBaseUrl } = await loadJsConfig(dir, config);
const supportedBrowsers = await getSupportedBrowsers(dir, dev, config);
return {
jsConfig,
resolvedBaseUrl,
supportedBrowsers
};
}
const UNSAFE_CACHE_REGEX = /[\\/]pages[\\/][^\\/]+(?:$|\?|#)/;
export default async function getBaseWebpackConfig(dir, { buildId , config , compilerType , dev =false , entrypoints , isDevFallback =false , pagesDir , reactProductionProfiling =false , rewrites , originalRewrites , originalRedirects , runWebpackSpan , appDir , middlewareMatchers , noMangling =false , jsConfig , resolvedBaseUrl , supportedBrowsers , clientRouterFilters , previewModeId , fetchCacheKeyPrefix , allowedRevalidateHeaderKeys }) {
var _config_experimental, _config_experimental_sri, _config_experimental_sri1, _config_compiler, _config_compiler1, _config_compiler2, _jsConfig_compilerOptions, _config_compiler3, _jsConfig_compilerOptions1, _config_compiler4, // allows add JsConfigPathsPlugin to allow hot-reloading
// if the config is added/removed
_webpackConfig_resolve, _webpackConfig_resolve_plugins, _jsConfig_compilerOptions2, _config_compiler5, _config_compiler6, _config_compiler7, _config_compiler8, _config_compiler9, _config_experimental1, _webpackConfig_module, _webpackConfig_module1, _webpackConfig_module_rules;
const isClient = compilerType === COMPILER_NAMES.client;
const isEdgeServer = compilerType === COMPILER_NAMES.edgeServer;
const isNodeServer = compilerType === COMPILER_NAMES.server;
const hasRewrites = rewrites.beforeFiles.length > 0 || rewrites.afterFiles.length > 0 || rewrites.fallback.length > 0;
const hasAppDir = !!config.experimental.appDir && !!appDir;
const hasServerComponents = hasAppDir;
const disableOptimizedLoading = true;
const enableTypedRoutes = !!config.experimental.typedRoutes && hasAppDir;
const useServerActions = !!config.experimental.serverActions && hasAppDir;
const bundledReactChannel = useServerActions ? "-experimental" : "";
if (isClient) {
if (// @ts-expect-error: experimental.runtime is deprecated
isEdgeRuntime(config.experimental.runtime)) {
Log.warn("You are using `experimental.runtime` which was removed. Check https://nextjs.org/docs/api-routes/edge-api-routes on how to use edge runtime.");
}
}
const babelConfigFile = await getBabelConfigFile(dir);
const distDir = path.join(dir, config.distDir);
let useSWCLoader = !babelConfigFile || config.experimental.forceSwcTransforms;
let SWCBinaryTarget = undefined;
if (useSWCLoader) {
var _require, _require_getBinaryMetadata;
// TODO: we do not collect wasm target yet
const binaryTarget = (_require = require("./swc")) == null ? void 0 : _require.getBinaryMetadata == null ? void 0 : (_require_getBinaryMetadata = _require.getBinaryMetadata()) == null ? void 0 : _require_getBinaryMetadata.target;
SWCBinaryTarget = binaryTarget ? [
`swc/target/${binaryTarget}`,
true
] : undefined;
}
if (!loggedSwcDisabled && !useSWCLoader && babelConfigFile) {
Log.info(`Disabled SWC as replacement for Babel because of custom Babel configuration "${path.relative(dir, babelConfigFile)}" https://nextjs.org/docs/messages/swc-disabled`);
loggedSwcDisabled = true;
}
// eagerly load swc bindings instead of waiting for transform calls
if (!babelConfigFile && isClient) {
await loadBindings();
}
if (!loggedIgnoredCompilerOptions && !useSWCLoader && config.compiler) {
Log.info("`compiler` options in `next.config.js` will be ignored while using Babel https://nextjs.org/docs/messages/ignored-compiler-options");
loggedIgnoredCompilerOptions = true;
}
const getBabelLoader = ()=>{
return {
loader: require.resolve("./babel/loader/index"),
options: {
configFile: babelConfigFile,
isServer: isNodeServer || isEdgeServer,
distDir,
pagesDir,
cwd: dir,
development: dev,
hasServerComponents,
hasReactRefresh: dev && isClient,
hasJsxRuntime: true
}
};
};
let swcTraceProfilingInitialized = false;
const getSwcLoader = (extraOptions)=>{
var _config_experimental;
if ((config == null ? void 0 : (_config_experimental = config.experimental) == null ? void 0 : _config_experimental.swcTraceProfiling) && !swcTraceProfilingInitialized) {
var _require;
// This will init subscribers once only in a single process lifecycle,
// even though it can be called multiple times.
// Subscriber need to be initialized _before_ any actual swc's call (transform, etcs)
// to collect correct trace spans when they are called.
swcTraceProfilingInitialized = true;
(_require = require("./swc")) == null ? void 0 : _require.initCustomTraceSubscriber == null ? void 0 : _require.initCustomTraceSubscriber(path.join(distDir, `swc-trace-profile-${Date.now()}.json`));
}
return {
loader: "next-swc-loader",
options: {
isServer: isNodeServer || isEdgeServer,
rootDir: dir,
pagesDir,
appDir,
hasReactRefresh: dev && isClient,
hasServerComponents: true,
fileReading: config.experimental.swcFileReading,
nextConfig: config,
jsConfig,
supportedBrowsers,
swcCacheDir: path.join(dir, (config == null ? void 0 : config.distDir) ?? ".next", "cache", "swc"),
...extraOptions
}
};
};
const defaultLoaders = {
babel: useSWCLoader ? getSwcLoader() : getBabelLoader()
};
const swcLoaderForServerLayer = hasServerComponents ? useSWCLoader ? [
getSwcLoader({
isServerLayer: true
})
] : // as an additional pass to handle RSC correctly.
// This will cause some performance overhead but
// acceptable as Babel will not be recommended.
[
getSwcLoader({
isServerLayer: true
}),
getBabelLoader()
] : [];
const swcLoaderForClientLayer = hasServerComponents ? useSWCLoader ? [
getSwcLoader({
hasServerComponents,
isServerLayer: false
})
] : // as an additional pass to handle RSC correctly.
// This will cause some performance overhead but
// acceptable as Babel will not be recommended.
[
getSwcLoader({
isServerLayer: false
}),
getBabelLoader()
] : [];
const swcLoaderForMiddlewareLayer = useSWCLoader ? getSwcLoader({
hasServerComponents: false
}) : // for middleware to tree shake the unused default optimized imports like "next/server".
// This will cause some performance overhead but
// acceptable as Babel will not be recommended.
[
getSwcLoader({
hasServerComponents: false
}),
getBabelLoader()
];
// Loader for API routes needs to be differently configured as it shouldn't
// have RSC transpiler enabled, so syntax checks such as invalid imports won't
// be performed.
const loaderForAPIRoutes = hasServerComponents && useSWCLoader ? {
loader: "next-swc-loader",
options: {
...getSwcLoader().options,
hasServerComponents: false
}
} : defaultLoaders.babel;
const pageExtensions = config.pageExtensions;
const outputPath = isNodeServer || isEdgeServer ? path.join(distDir, SERVER_DIRECTORY) : distDir;
const reactServerCondition = [
"react-server",
...isEdgeServer ? edgeConditionNames : [],
// inherits the default conditions
"..."
];
const clientEntries = isClient ? {
// Backwards compatibility
"main.js": [],
...dev ? {
[CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH]: require.resolve(`next/dist/compiled/@next/react-refresh-utils/dist/runtime`),
[CLIENT_STATIC_FILES_RUNTIME_AMP]: `./` + path.relative(dir, path.join(NEXT_PROJECT_ROOT_DIST_CLIENT, "dev", "amp-dev")).replace(/\\/g, "/")
} : {},
[CLIENT_STATIC_FILES_RUNTIME_MAIN]: `./` + path.relative(dir, path.join(NEXT_PROJECT_ROOT_DIST_CLIENT, dev ? `next-dev.js` : "next.js")).replace(/\\/g, "/"),
...hasAppDir ? {
[CLIENT_STATIC_FILES_RUNTIME_MAIN_APP]: dev ? [
require.resolve(`next/dist/compiled/@next/react-refresh-utils/dist/runtime`),
`./` + path.relative(dir, path.join(NEXT_PROJECT_ROOT_DIST_CLIENT, "app-next-dev.js")).replace(/\\/g, "/")
] : [
`./` + path.relative(dir, path.join(NEXT_PROJECT_ROOT_DIST_CLIENT, "app-next.js")).replace(/\\/g, "/")
]
} : {}
} : undefined;
// tell webpack where to look for _app and _document
// using aliases to allow falling back to the default
// version when removed or not present
const clientResolveRewrites = require.resolve("../shared/lib/router/utils/resolve-rewrites");
const customAppAliases = {};
const customErrorAlias = {};
const customDocumentAliases = {};
const customRootAliases = {};
if (dev) {
const nextDist = "next/dist/" + (isEdgeServer ? "esm/" : "");
customAppAliases[`${PAGES_DIR_ALIAS}/_app`] = [
...pagesDir ? pageExtensions.reduce((prev, ext)=>{
prev.push(path.join(pagesDir, `_app.${ext}`));
return prev;
}, []) : [],
`${nextDist}pages/_app.js`
];
customAppAliases[`${PAGES_DIR_ALIAS}/_error`] = [
...pagesDir ? pageExtensions.reduce((prev, ext)=>{
prev.push(path.join(pagesDir, `_error.${ext}`));
return prev;
}, []) : [],
`${nextDist}pages/_error.js`
];
customDocumentAliases[`${PAGES_DIR_ALIAS}/_document`] = [
...pagesDir ? pageExtensions.reduce((prev, ext)=>{
prev.push(path.join(pagesDir, `_document.${ext}`));
return prev;
}, []) : [],
`${nextDist}pages/_document.js`
];
}
let hasExternalOtelApiPackage = false;
try {
const opentelemetryPackageJson = require("@opentelemetry/api/package.json");
if (opentelemetryPackageJson.version) {
// 0.19.0 is the first version of the package that has the `tracer.getSpan` API that we need:
// https://github.com/vercel/next.js/issues/48118
if (semver.gte(opentelemetryPackageJson.version, "0.19.0")) {
hasExternalOtelApiPackage = true;
} else {
throw new Error(`Installed "@opentelemetry/api" with version ${opentelemetryPackageJson.version} is not supported by Next.js. Please upgrade to 0.19.0 or newer version.`);
}
}
} catch {}
const resolveConfig = {
// Disable .mjs for node_modules bundling
extensions: isNodeServer ? [
".js",
".mjs",
".tsx",
".ts",
".jsx",
".json",
".wasm"
] : [
".mjs",
".js",
".tsx",
".ts",
".jsx",
".json",
".wasm"
],
extensionAlias: config.experimental.extensionAlias,
modules: [
"node_modules",
...nodePathList
],
alias: {
// Alias 3rd party @vercel/og package to vendored og image package to reduce bundle size
"@vercel/og": "next/dist/server/web/spec-extension/image-response",
// Alias next/dist imports to next/dist/esm assets,
// let this alias hit before `next` alias.
...isEdgeServer ? {
"next/dist/client": "next/dist/esm/client",
"next/dist/shared": "next/dist/esm/shared",
"next/dist/pages": "next/dist/esm/pages",
"next/dist/lib": "next/dist/esm/lib",
"next/dist/server": "next/dist/esm/server",
// Alias the usage of next public APIs
[`${NEXT_PROJECT_ROOT}/server`]: "next/dist/esm/server/web/exports/index",
[`${NEXT_PROJECT_ROOT}/dist/client/link`]: "next/dist/esm/client/link",
[`${NEXT_PROJECT_ROOT}/dist/shared/lib/image-external`]: "next/dist/esm/shared/lib/image-external",
[`${NEXT_PROJECT_ROOT}/dist/client/script`]: "next/dist/esm/client/script",
[`${NEXT_PROJECT_ROOT}/dist/client/router`]: "next/dist/esm/client/router",
[`${NEXT_PROJECT_ROOT}/dist/shared/lib/head`]: "next/dist/esm/shared/lib/head",
[`${NEXT_PROJECT_ROOT}/dist/shared/lib/dynamic`]: "next/dist/esm/shared/lib/dynamic",
[`${NEXT_PROJECT_ROOT}/dist/pages/_document`]: "next/dist/esm/pages/_document",
[`${NEXT_PROJECT_ROOT}/dist/pages/_app`]: "next/dist/esm/pages/_app",
[`${NEXT_PROJECT_ROOT}/dist/client/components/navigation`]: "next/dist/esm/client/components/navigation",
[`${NEXT_PROJECT_ROOT}/dist/client/components/headers`]: "next/dist/esm/client/components/headers"
} : undefined,
// For RSC server bundle
...!hasExternalOtelApiPackage && {
"@opentelemetry/api": "next/dist/compiled/@opentelemetry/api"
},
...config.images.loaderFile ? {
"next/dist/shared/lib/image-loader": config.images.loaderFile,
...isEdgeServer && {
"next/dist/esm/shared/lib/image-loader": config.images.loaderFile
}
} : undefined,
next: NEXT_PROJECT_ROOT,
"styled-jsx/style$": require.resolve(`styled-jsx/style`),
"styled-jsx$": require.resolve(`styled-jsx`),
...customAppAliases,
...customErrorAlias,
...customDocumentAliases,
...customRootAliases,
...pagesDir ? {
[PAGES_DIR_ALIAS]: pagesDir
} : {},
...appDir ? {
[APP_DIR_ALIAS]: appDir
} : {},
[ROOT_DIR_ALIAS]: dir,
[DOT_NEXT_ALIAS]: distDir,
...isClient || isEdgeServer ? getOptimizedAliases() : {},
...reactProductionProfiling ? getReactProfilingInProduction() : {},
[RSC_ACTION_VALIDATE_ALIAS]: "next/dist/build/webpack/loaders/next-flight-loader/action-validate",
[RSC_ACTION_CLIENT_WRAPPER_ALIAS]: "next/dist/build/webpack/loaders/next-flight-loader/action-client-wrapper",
[RSC_ACTION_PROXY_ALIAS]: "next/dist/build/webpack/loaders/next-flight-loader/action-proxy",
...isClient || isEdgeServer ? {
[clientResolveRewrites]: hasRewrites ? clientResolveRewrites : false
} : {},
"@swc/helpers/_": path.join(path.dirname(require.resolve("@swc/helpers/package.json")), "_"),
setimmediate: "next/dist/compiled/setimmediate"
},
...isClient || isEdgeServer ? {
fallback: {
process: require.resolve("./polyfills/process")
}
} : undefined,
mainFields: mainFieldsPerCompiler[compilerType],
...isEdgeServer && {
conditionNames: edgeConditionNames
},
plugins: []
};
const terserOptions = {
parse: {
ecma: 8
},
compress: {
ecma: 5,
warnings: false,
// The following two options are known to break valid JavaScript code
comparisons: false,
inline: 2
},
mangle: {
safari10: true,
...process.env.__NEXT_MANGLING_DEBUG || noMangling ? {
toplevel: true,
module: true,
keep_classnames: true,
keep_fnames: true
} : {}
},
output: {
ecma: 5,
safari10: true,
comments: false,
// Fixes usage of Emoji and certain Regex
ascii_only: true,
...process.env.__NEXT_MANGLING_DEBUG || noMangling ? {
beautify: true
} : {}
}
};
// Packages which will be split into the 'framework' chunk.
// Only top-level packages are included, e.g. nested copies like
// 'node_modules/meow/node_modules/object-assign' are not included.
const topLevelFrameworkPaths = [];
const visitedFrameworkPackages = new Set();
// Adds package-paths of dependencies recursively
const addPackagePath = (packageName, relativeToPath)=>{
try {
if (visitedFrameworkPackages.has(packageName)) {
return;
}
visitedFrameworkPackages.add(packageName);
const packageJsonPath = require.resolve(`${packageName}/package.json`, {
paths: [
relativeToPath
]
});
// Include a trailing slash so that a `.startsWith(packagePath)` check avoids false positives
// when one package name starts with the full name of a different package.
// For example:
// "node_modules/react-slider".startsWith("node_modules/react") // true
// "node_modules/react-slider".startsWith("node_modules/react/") // false
const directory = path.join(packageJsonPath, "../");
// Returning from the function in case the directory has already been added and traversed
if (topLevelFrameworkPaths.includes(directory)) return;
topLevelFrameworkPaths.push(directory);
const dependencies = require(packageJsonPath).dependencies || {};
for (const name of Object.keys(dependencies)){
addPackagePath(name, directory);
}
} catch (_) {
// don't error on failing to resolve framework packages
}
};
for (const packageName of [
"react",
"react-dom"
]){
addPackagePath(packageName, dir);
}
const crossOrigin = config.crossOrigin;
const looseEsmExternals = ((_config_experimental = config.experimental) == null ? void 0 : _config_experimental.esmExternals) === "loose";
const optOutBundlingPackages = EXTERNAL_PACKAGES.concat(...config.experimental.serverComponentsExternalPackages || []);
const optOutBundlingPackageRegex = new RegExp(`[/\\\\]node_modules[/\\\\](${optOutBundlingPackages.map((p)=>p.replace(/\//g, "[/\\\\]")).join("|")})[/\\\\]`);
let resolvedExternalPackageDirs;
async function handleExternals(context, request, dependencyType, layer, getResolve) {
// We need to externalize internal requests for files intended to
// not be bundled.
const isLocal = request.startsWith(".") || // Always check for unix-style path, as webpack sometimes
// normalizes as posix.
path.posix.isAbsolute(request) || // When on Windows, we also want to check for Windows-specific
// absolute paths.
process.platform === "win32" && path.win32.isAbsolute(request);
// make sure import "next" shows a warning when imported
// in pages/components
if (request === "next") {
return `commonjs next/dist/lib/import-next-warning`;
}
const isAppLayer = [
WEBPACK_LAYERS.reactServerComponents,
WEBPACK_LAYERS.serverSideRendering,
WEBPACK_LAYERS.appPagesBrowser,
WEBPACK_LAYERS.actionBrowser
].includes(layer);
if (request === "react/jsx-dev-runtime" || request === "react/jsx-runtime") {
if (isAppLayer) {
return `commonjs next/dist/compiled/${request.replace("react", "react" + bundledReactChannel)}`;
}
return;
}
// Special internal modules that must be bundled for Server Components.
if (layer === WEBPACK_LAYERS.reactServerComponents) {
// React needs to be bundled for Server Components so the special
// `react-server` export condition can be used.
if (reactPackagesRegex.test(request)) {
return;
}
}
// Relative requires don't need custom resolution, because they
// are relative to requests we've already resolved here.
// Absolute requires (require('/foo')) are extremely uncommon, but
// also have no need for customization as they're already resolved.
if (!isLocal) {
if (/^(?:next$)/.test(request)) {
return `commonjs ${request}`;
}
if (reactPackagesRegex.test(request)) {
// override react-dom to server-rendering-stub for server
if (request === "react-dom" && (layer === WEBPACK_LAYERS.serverSideRendering || layer === WEBPACK_LAYERS.reactServerComponents || layer === WEBPACK_LAYERS.actionBrowser)) {
request = `next/dist/compiled/react-dom${bundledReactChannel}/server-rendering-stub`;
} else if (isAppLayer) {
request = "next/dist/compiled/" + request.replace(/^(react-server-dom-webpack|react-dom|react)/, (name)=>{
return name + bundledReactChannel;
});
}
return `commonjs ${request}`;
}
const notExternalModules = /^(?:private-next-pages\/|next\/(?:dist\/pages\/|(?:app|document|link|image|legacy\/image|constants|dynamic|script|navigation|headers)$)|string-hash|private-next-rsc-action-validate|private-next-rsc-action-client-wrapper|private-next-rsc-action-proxy$)/;
if (notExternalModules.test(request)) {
return;
}
}
// @swc/helpers should not be external as it would
// require hoisting the package which we can't rely on
if (request.includes("@swc/helpers")) {
return;
}
// When in esm externals mode, and using import, we resolve with
// ESM resolving options.
// Also disable esm request when appDir is enabled
const isEsmRequested = dependencyType === "esm";
const isLocalCallback = (localRes)=>{
// Makes sure dist/shared and dist/server are not bundled
// we need to process shared `router/router`, `head` and `dynamic`,
// so that the DefinePlugin can inject process.env values.
// Treat next internals as non-external for server layer
if (isWebpackServerLayer(layer)) {
return;
}
const isNextExternal = /next[/\\]dist[/\\](esm[\\/])?(shared|server)[/\\](?!lib[/\\](router[/\\]router|dynamic|app-dynamic|image-external|lazy-dynamic|head[^-]))/.test(localRes) || // There's no need to bundle the dev overlay
process.env.NODE_ENV === "development" && /next[/\\]dist[/\\](esm[/\\])?client[/\\]components[/\\]react-dev-overlay[/\\]/.test(localRes);
if (isNextExternal) {
// Generate Next.js external import
const externalRequest = path.posix.join("next", "dist", path.relative(// Root of Next.js package:
path.join(__dirname, ".."), localRes)// Windows path normalization
.replace(/\\/g, "/"));
return `commonjs ${externalRequest}`;
}
};
// Don't bundle @vercel/og nodejs bundle for nodejs runtime.
// TODO-APP: bundle route.js with different layer that externals common node_module deps.
if (isWebpackServerLayer(layer) && request === "next/dist/compiled/@vercel/og/index.node.js") {
return `module ${request}`;
}
// Specific Next.js imports that should remain external
// TODO-APP: Investigate if we can remove this.
if (request.startsWith("next/dist/")) {
// Image loader needs to be transpiled
if (/^next\/dist\/shared\/lib\/image-loader/.test(request)) {
return;
}
if (/^next\/dist\/shared\/(?!lib\/router\/router)/.test(request) || /^next\/dist\/compiled\/.*\.c?js$/.test(request)) {
return `commonjs ${request}`;
}
if (/^next\/dist\/esm\/shared\/(?!lib\/router\/router)/.test(request) || /^next\/dist\/compiled\/.*\.mjs$/.test(request)) {
return `module ${request}`;
}
// Other Next.js internals need to be transpiled.
return;
}
// Early return if the request needs to be bundled, such as in the client layer.
// Treat react packages and next internals as external for SSR layer,
// also map react to builtin ones with require-hook.
if (layer === WEBPACK_LAYERS.serverSideRendering) {
if (reactPackagesRegex.test(request)) {
return `commonjs next/dist/compiled/${request.replace(/^(react-server-dom-webpack|react-dom|react)/, (name)=>{
return name + bundledReactChannel;
})}`;
}
const isRelative = request.startsWith(".");
const fullRequest = isRelative ? path.join(context, request).replace(/\\/g, "/") : request;
const resolveNextExternal = isLocalCallback(fullRequest);
return resolveNextExternal;
}
// TODO-APP: Let's avoid this resolve call as much as possible, and eventually get rid of it.
const resolveResult = await resolveExternal(dir, config.experimental.esmExternals, context, request, isEsmRequested, hasAppDir, getResolve, isLocal ? isLocalCallback : undefined);
if ("localRes" in resolveResult) {
return resolveResult.localRes;