next
Version:
The React Framework
819 lines (818 loc) • 91.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = build;
var _env = require("@next/env");
var _chalk = _interopRequireDefault(require("next/dist/compiled/chalk"));
var _crypto = _interopRequireDefault(require("crypto"));
var _micromatch = require("next/dist/compiled/micromatch");
var _fs = require("fs");
var _jestWorker = require("next/dist/compiled/jest-worker");
var _worker = require("../lib/worker");
var _devalue = _interopRequireDefault(require("next/dist/compiled/devalue"));
var _escapeRegexp = require("../shared/lib/escape-regexp");
var _findUp = _interopRequireDefault(require("next/dist/compiled/find-up"));
var _indexCjs = require("next/dist/compiled/nanoid/index.cjs");
var _pathToRegexp = require("next/dist/compiled/path-to-regexp");
var _path = _interopRequireWildcard(require("path"));
var _formatWebpackMessages = _interopRequireDefault(require("../client/dev/error-overlay/format-webpack-messages"));
var _constants = require("../lib/constants");
var _fileExists = require("../lib/file-exists");
var _findPagesDir = require("../lib/find-pages-dir");
var _loadCustomRoutes = _interopRequireWildcard(require("../lib/load-custom-routes"));
var _redirectStatus = require("../lib/redirect-status");
var _nonNullable = require("../lib/non-nullable");
var _recursiveDelete = require("../lib/recursive-delete");
var _verifyAndLint = require("../lib/verifyAndLint");
var _verifyPartytownSetup = require("../lib/verify-partytown-setup");
var _constants1 = require("../shared/lib/constants");
var _utils = require("../shared/lib/router/utils");
var _config = _interopRequireDefault(require("../server/config"));
var _utils1 = require("../server/utils");
var _normalizePagePath = require("../shared/lib/page-path/normalize-page-path");
var _require = require("../server/require");
var ciEnvironment = _interopRequireWildcard(require("../telemetry/ci-info"));
var _events = require("../telemetry/events");
var _storage = require("../telemetry/storage");
var _compiler = require("./compiler");
var _getPageStaticInfo = require("./analysis/get-page-static-info");
var _entries = require("./entries");
var _generateBuildId = require("./generate-build-id");
var _isWriteable = require("./is-writeable");
var Log = _interopRequireWildcard(require("./output/log"));
var _spinner = _interopRequireDefault(require("./spinner"));
var _trace = require("../trace");
var _utils2 = require("./utils");
var _webpackConfig = _interopRequireDefault(require("./webpack-config"));
var _writeBuildId = require("./write-build-id");
var _normalizeLocalePath = require("../shared/lib/i18n/normalize-locale-path");
var _isError = _interopRequireDefault(require("../lib/is-error"));
var _telemetryPlugin = require("./webpack/plugins/telemetry-plugin");
var _recursiveCopy = require("../lib/recursive-copy");
var _recursiveReaddir = require("../lib/recursive-readdir");
var _swc = require("./swc");
var _flightClientEntryPlugin = require("./webpack/plugins/flight-client-entry-plugin");
var _routeRegex = require("../shared/lib/router/utils/route-regex");
var _flatReaddir = require("../lib/flat-readdir");
var _swcPlugins = require("../telemetry/events/swc-plugins");
var _appPaths = require("../shared/lib/router/utils/app-paths");
async function build(dir, conf = null, reactProductionProfiling = false, debugOutput = false, runLint = true) {
try {
const nextBuildSpan = (0, _trace).trace("next-build", undefined, {
version: "12.2.6"
});
const buildResult = await nextBuildSpan.traceAsyncFn(async ()=>{
var ref8, ref1, ref2;
// attempt to load global env values so they are available in next.config.js
const { loadedEnvFiles } = nextBuildSpan.traceChild("load-dotenv").traceFn(()=>(0, _env).loadEnvConfig(dir, false, Log));
const config = await nextBuildSpan.traceChild("load-next-config").traceAsyncFn(()=>(0, _config).default(_constants1.PHASE_PRODUCTION_BUILD, dir, conf));
const distDir = _path.default.join(dir, config.distDir);
(0, _trace).setGlobal("phase", _constants1.PHASE_PRODUCTION_BUILD);
(0, _trace).setGlobal("distDir", distDir);
// We enable concurrent features (Fizz-related rendering architecture) when
// using React 18 or experimental.
const hasReactRoot = !!process.env.__NEXT_REACT_ROOT;
const hasServerComponents = hasReactRoot && !!config.experimental.serverComponents;
const { target } = config;
const buildId = await nextBuildSpan.traceChild("generate-buildid").traceAsyncFn(()=>(0, _generateBuildId).generateBuildId(config.generateBuildId, _indexCjs.nanoid));
const customRoutes = await nextBuildSpan.traceChild("load-custom-routes").traceAsyncFn(()=>(0, _loadCustomRoutes).default(config));
const { headers , rewrites , redirects } = customRoutes;
const cacheDir = _path.default.join(distDir, "cache");
if (ciEnvironment.isCI && !ciEnvironment.hasNextSupport) {
const hasCache = await (0, _fileExists).fileExists(cacheDir);
if (!hasCache) {
// Intentionally not piping to stderr in case people fail in CI when
// stderr is detected.
console.log(`${Log.prefixes.warn} No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache`);
}
}
const telemetry = new _storage.Telemetry({
distDir
});
(0, _trace).setGlobal("telemetry", telemetry);
const publicDir = _path.default.join(dir, "public");
const { pages: pagesDir , appDir } = (0, _findPagesDir).findPagesDir(dir, config.experimental.appDir);
const hasPublicDir = await (0, _fileExists).fileExists(publicDir);
telemetry.record((0, _events).eventCliSession(dir, config, {
webpackVersion: 5,
cliCommand: "build",
isSrcDir: _path.default.relative(dir, pagesDir).startsWith("src"),
hasNowJson: !!await (0, _findUp).default("now.json", {
cwd: dir
}),
isCustomServer: null
}));
(0, _events).eventNextPlugins(_path.default.resolve(dir)).then((events)=>telemetry.record(events));
(0, _swcPlugins).eventSwcPlugins(_path.default.resolve(dir), config).then((events)=>telemetry.record(events));
const ignoreTypeScriptErrors = Boolean(config.typescript.ignoreBuildErrors);
const ignoreESLint = Boolean(config.eslint.ignoreDuringBuilds);
const eslintCacheDir = _path.default.join(cacheDir, "eslint/");
const shouldLint = !ignoreESLint && runLint;
if (ignoreTypeScriptErrors) {
Log.info("Skipping validation of types");
}
if (runLint && ignoreESLint) {
// only print log when build requre lint while ignoreESLint is enabled
Log.info("Skipping linting");
}
let typeCheckingAndLintingSpinnerPrefixText;
let typeCheckingAndLintingSpinner;
if (!ignoreTypeScriptErrors && shouldLint) {
typeCheckingAndLintingSpinnerPrefixText = "Linting and checking validity of types";
} else if (!ignoreTypeScriptErrors) {
typeCheckingAndLintingSpinnerPrefixText = "Checking validity of types";
} else if (shouldLint) {
typeCheckingAndLintingSpinnerPrefixText = "Linting";
}
// we will not create a spinner if both ignoreTypeScriptErrors and ignoreESLint are
// enabled, but we will still verifying project's tsconfig and dependencies.
if (typeCheckingAndLintingSpinnerPrefixText) {
typeCheckingAndLintingSpinner = (0, _spinner).default({
prefixText: `${Log.prefixes.info} ${typeCheckingAndLintingSpinnerPrefixText}`
});
}
const typeCheckStart = process.hrtime();
const [[verifyResult, typeCheckEnd]] = await Promise.all([
nextBuildSpan.traceChild("verify-typescript-setup").traceAsyncFn(()=>verifyTypeScriptSetup(dir, [
pagesDir,
appDir
].filter(Boolean), !ignoreTypeScriptErrors, config.typescript.tsconfigPath, config.images.disableStaticImages, cacheDir, config.experimental.cpus, config.experimental.workerThreads).then((resolved)=>{
const checkEnd = process.hrtime(typeCheckStart);
return [
resolved,
checkEnd
];
})),
shouldLint && nextBuildSpan.traceChild("verify-and-lint").traceAsyncFn(async ()=>{
var ref;
await (0, _verifyAndLint).verifyAndLint(dir, eslintCacheDir, (ref = config.eslint) == null ? void 0 : ref.dirs, config.experimental.cpus, config.experimental.workerThreads, telemetry);
}),
]);
typeCheckingAndLintingSpinner == null ? void 0 : typeCheckingAndLintingSpinner.stopAndPersist();
if (!ignoreTypeScriptErrors && verifyResult) {
var ref3, ref4, ref5;
telemetry.record((0, _events).eventTypeCheckCompleted({
durationInSeconds: typeCheckEnd[0],
typescriptVersion: verifyResult.version,
inputFilesCount: (ref3 = verifyResult.result) == null ? void 0 : ref3.inputFilesCount,
totalFilesCount: (ref4 = verifyResult.result) == null ? void 0 : ref4.totalFilesCount,
incremental: (ref5 = verifyResult.result) == null ? void 0 : ref5.incremental
}));
}
const buildLintEvent = {
featureName: "build-lint",
invocationCount: shouldLint ? 1 : 0
};
telemetry.record({
eventName: _events.EVENT_BUILD_FEATURE_USAGE,
payload: buildLintEvent
});
const buildSpinner = (0, _spinner).default({
prefixText: `${Log.prefixes.info} Creating an optimized production build`
});
const isLikeServerless = (0, _utils1).isTargetLikeServerless(target);
const pagesPaths = await nextBuildSpan.traceChild("collect-pages").traceAsyncFn(()=>(0, _recursiveReaddir).recursiveReadDir(pagesDir, new RegExp(`\\.(?:${config.pageExtensions.join("|")})$`)));
let appPaths;
if (appDir) {
appPaths = await nextBuildSpan.traceChild("collect-app-paths").traceAsyncFn(()=>(0, _recursiveReaddir).recursiveReadDir(appDir, new RegExp(`page\\.(?:${config.pageExtensions.join("|")})$`)));
}
const middlewareDetectionRegExp = new RegExp(`^${_constants.MIDDLEWARE_FILENAME}\\.(?:${config.pageExtensions.join("|")})$`);
const rootPaths = (await (0, _flatReaddir).flatReaddir((0, _path).join(pagesDir, ".."), middlewareDetectionRegExp)).map((absoluteFile)=>absoluteFile.replace(dir, ""));
// needed for static exporting since we want to replace with HTML
// files
const allStaticPages = new Set();
let allPageInfos = new Map();
const previewProps = {
previewModeId: _crypto.default.randomBytes(16).toString("hex"),
previewModeSigningKey: _crypto.default.randomBytes(32).toString("hex"),
previewModeEncryptionKey: _crypto.default.randomBytes(32).toString("hex")
};
const mappedPages = nextBuildSpan.traceChild("create-pages-mapping").traceFn(()=>(0, _entries).createPagesMapping({
hasServerComponents,
isDev: false,
pageExtensions: config.pageExtensions,
pagesType: "pages",
pagePaths: pagesPaths
}));
let mappedAppPages;
if (appPaths && appDir) {
mappedAppPages = nextBuildSpan.traceChild("create-app-mapping").traceFn(()=>(0, _entries).createPagesMapping({
pagePaths: appPaths,
hasServerComponents,
isDev: false,
pagesType: "app",
pageExtensions: config.pageExtensions
}));
}
let mappedRootPaths = {};
if (rootPaths.length > 0) {
mappedRootPaths = (0, _entries).createPagesMapping({
hasServerComponents,
isDev: false,
pageExtensions: config.pageExtensions,
pagePaths: rootPaths,
pagesType: "root"
});
}
const entrypoints = await nextBuildSpan.traceChild("create-entrypoints").traceAsyncFn(()=>(0, _entries).createEntrypoints({
buildId,
config,
envFiles: loadedEnvFiles,
isDev: false,
pages: mappedPages,
pagesDir,
previewMode: previewProps,
target,
rootDir: dir,
rootPaths: mappedRootPaths,
appDir,
appPaths: mappedAppPages,
pageExtensions: config.pageExtensions
}));
const pageKeys = {
pages: Object.keys(mappedPages),
app: mappedAppPages ? Object.keys(mappedAppPages).map((key)=>(0, _appPaths).normalizeAppPath(key)) : undefined
};
const conflictingPublicFiles = [];
const hasPages404 = (ref8 = mappedPages["/404"]) == null ? void 0 : ref8.startsWith(_constants.PAGES_DIR_ALIAS);
const hasCustomErrorPage = mappedPages["/_error"].startsWith(_constants.PAGES_DIR_ALIAS);
if (hasPublicDir) {
const hasPublicUnderScoreNextDir = await (0, _fileExists).fileExists(_path.default.join(publicDir, "_next"));
if (hasPublicUnderScoreNextDir) {
throw new Error(_constants.PUBLIC_DIR_MIDDLEWARE_CONFLICT);
}
}
await nextBuildSpan.traceChild("public-dir-conflict-check").traceAsyncFn(async ()=>{
// Check if pages conflict with files in `public`
// Only a page of public file can be served, not both.
for(const page in mappedPages){
const hasPublicPageFile = await (0, _fileExists).fileExists(_path.default.join(publicDir, page === "/" ? "/index" : page), "file");
if (hasPublicPageFile) {
conflictingPublicFiles.push(page);
}
}
const numConflicting = conflictingPublicFiles.length;
if (numConflicting) {
throw new Error(`Conflicting public and page file${numConflicting === 1 ? " was" : "s were"} found. https://nextjs.org/docs/messages/conflicting-public-file-page\n${conflictingPublicFiles.join("\n")}`);
}
});
const nestedReservedPages = pageKeys.pages.filter((page)=>{
return page.match(/\/(_app|_document|_error)$/) && _path.default.dirname(page) !== "/";
});
if (nestedReservedPages.length) {
Log.warn(`The following reserved Next.js pages were detected not directly under the pages directory:\n` + nestedReservedPages.join("\n") + `\nSee more info here: https://nextjs.org/docs/messages/nested-reserved-page\n`);
}
const restrictedRedirectPaths = [
"/_next"
].map((p)=>config.basePath ? `${config.basePath}${p}` : p);
const buildCustomRoute = (r, type)=>{
const keys = [];
const routeRegex = (0, _pathToRegexp).pathToRegexp(r.source, keys, {
strict: true,
sensitive: false,
delimiter: "/"
});
let regexSource = routeRegex.source;
if (!r.internal) {
regexSource = (0, _redirectStatus).modifyRouteRegex(routeRegex.source, type === "redirect" ? restrictedRedirectPaths : undefined);
}
return {
...r,
...type === "redirect" ? {
statusCode: (0, _redirectStatus).getRedirectStatus(r),
permanent: undefined
} : {},
regex: (0, _loadCustomRoutes).normalizeRouteRegex(regexSource)
};
};
const routesManifestPath = _path.default.join(distDir, _constants1.ROUTES_MANIFEST);
const routesManifest = nextBuildSpan.traceChild("generate-routes-manifest").traceFn(()=>{
var _app;
const sortedRoutes = (0, _utils).getSortedRoutes([
...pageKeys.pages,
...(_app = pageKeys.app) != null ? _app : [],
]);
const dynamicRoutes = [];
const staticRoutes = [];
for (const route of sortedRoutes){
if ((0, _utils).isDynamicRoute(route)) {
dynamicRoutes.push(pageToRoute(route));
} else if (!(0, _utils2).isReservedPage(route)) {
staticRoutes.push(pageToRoute(route));
}
}
return {
version: 3,
pages404: true,
basePath: config.basePath,
redirects: redirects.map((r)=>buildCustomRoute(r, "redirect")),
headers: headers.map((r)=>buildCustomRoute(r, "header")),
dynamicRoutes,
staticRoutes,
dataRoutes: [],
i18n: config.i18n || undefined
};
});
if (rewrites.beforeFiles.length === 0 && rewrites.fallback.length === 0) {
routesManifest.rewrites = rewrites.afterFiles.map((r)=>buildCustomRoute(r, "rewrite"));
} else {
routesManifest.rewrites = {
beforeFiles: rewrites.beforeFiles.map((r)=>buildCustomRoute(r, "rewrite")),
afterFiles: rewrites.afterFiles.map((r)=>buildCustomRoute(r, "rewrite")),
fallback: rewrites.fallback.map((r)=>buildCustomRoute(r, "rewrite"))
};
}
const combinedRewrites = [
...rewrites.beforeFiles,
...rewrites.afterFiles,
...rewrites.fallback,
];
const distDirCreated = await nextBuildSpan.traceChild("create-dist-dir").traceAsyncFn(async ()=>{
try {
await _fs.promises.mkdir(distDir, {
recursive: true
});
return true;
} catch (err) {
if ((0, _isError).default(err) && err.code === "EPERM") {
return false;
}
throw err;
}
});
if (!distDirCreated || !await (0, _isWriteable).isWriteable(distDir)) {
throw new Error("> Build directory is not writeable. https://nextjs.org/docs/messages/build-dir-not-writeable");
}
if (config.cleanDistDir) {
await (0, _recursiveDelete).recursiveDelete(distDir, /^cache/);
}
// Ensure commonjs handling is used for files in the distDir (generally .next)
// Files outside of the distDir can be "type": "module"
await _fs.promises.writeFile(_path.default.join(distDir, "package.json"), '{"type": "commonjs"}');
// We need to write the manifest with rewrites before build
// so serverless can import the manifest
await nextBuildSpan.traceChild("write-routes-manifest").traceAsyncFn(()=>_fs.promises.writeFile(routesManifestPath, JSON.stringify(routesManifest), "utf8"));
const serverDir = isLikeServerless ? _constants1.SERVERLESS_DIRECTORY : _constants1.SERVER_DIRECTORY;
const manifestPath = _path.default.join(distDir, serverDir, _constants1.PAGES_MANIFEST);
const requiredServerFiles = nextBuildSpan.traceChild("generate-required-server-files").traceFn(()=>({
version: 1,
config: {
...config,
configFile: undefined,
experimental: {
...config.experimental,
trustHostHeader: ciEnvironment.hasNextSupport
}
},
appDir: dir,
files: [
_constants1.ROUTES_MANIFEST,
_path.default.relative(distDir, manifestPath),
_constants1.BUILD_MANIFEST,
_constants1.PRERENDER_MANIFEST,
_path.default.join(_constants1.SERVER_DIRECTORY, _constants1.MIDDLEWARE_MANIFEST),
...hasServerComponents ? [
_path.default.join(_constants1.SERVER_DIRECTORY, _constants1.FLIGHT_MANIFEST + ".js"),
_path.default.join(_constants1.SERVER_DIRECTORY, _constants1.FLIGHT_MANIFEST + ".json"),
] : [],
_constants1.REACT_LOADABLE_MANIFEST,
config.optimizeFonts ? _path.default.join(serverDir, _constants1.FONT_MANIFEST) : null,
_constants1.BUILD_ID_FILE,
appDir ? _path.default.join(serverDir, _constants1.APP_PATHS_MANIFEST) : null,
].filter(_nonNullable.nonNullable).map((file)=>_path.default.join(config.distDir, file)),
ignore: []
}));
let result = {
warnings: [],
errors: [],
stats: []
};
let webpackBuildStart;
let telemetryPlugin;
await (async ()=>{
var ref;
// IIFE to isolate locals and avoid retaining memory too long
const runWebpackSpan = nextBuildSpan.traceChild("run-webpack-compiler");
const commonWebpackOptions = {
buildId,
config,
hasReactRoot,
pagesDir,
reactProductionProfiling,
rewrites,
runWebpackSpan,
target,
appDir,
middlewareRegex: entrypoints.middlewareRegex
};
const configs = await runWebpackSpan.traceChild("generate-webpack-config").traceAsyncFn(()=>Promise.all([
(0, _webpackConfig).default(dir, {
...commonWebpackOptions,
compilerType: "client",
entrypoints: entrypoints.client
}),
(0, _webpackConfig).default(dir, {
...commonWebpackOptions,
compilerType: "server",
entrypoints: entrypoints.server
}),
(0, _webpackConfig).default(dir, {
...commonWebpackOptions,
compilerType: "edge-server",
entrypoints: entrypoints.edgeServer
}),
]));
const clientConfig = configs[0];
if (clientConfig.optimization && (clientConfig.optimization.minimize !== true || clientConfig.optimization.minimizer && clientConfig.optimization.minimizer.length === 0)) {
Log.warn(`Production code optimization has been disabled in your project. Read more: https://nextjs.org/docs/messages/minification-disabled`);
}
webpackBuildStart = process.hrtime();
// We run client and server compilation separately to optimize for memory usage
await runWebpackSpan.traceAsyncFn(async ()=>{
// If we are under the serverless build, we will have to run the client
// compiler first because the server compiler depends on the manifest
// files that are created by the client compiler.
// Otherwise, we run the server compilers first and then the client
// compiler to track the boundary of server/client components.
let clientResult = null;
let serverResult = null;
let edgeServerResult = null;
if (isLikeServerless) {
if (config.experimental.serverComponents) {
throw new Error("Server Components are not supported in serverless mode.");
}
// Build client first
clientResult = await (0, _compiler).runCompiler(clientConfig, {
runWebpackSpan
});
// Only continue if there were no errors
if (!clientResult.errors.length) {
serverResult = await (0, _compiler).runCompiler(configs[1], {
runWebpackSpan
});
edgeServerResult = configs[2] ? await (0, _compiler).runCompiler(configs[2], {
runWebpackSpan
}) : null;
}
} else {
// During the server compilations, entries of client components will be
// injected to this set and then will be consumed by the client compiler.
_flightClientEntryPlugin.injectedClientEntries.clear();
serverResult = await (0, _compiler).runCompiler(configs[1], {
runWebpackSpan
});
edgeServerResult = configs[2] ? await (0, _compiler).runCompiler(configs[2], {
runWebpackSpan
}) : null;
// Only continue if there were no errors
if (!serverResult.errors.length && !(edgeServerResult == null ? void 0 : edgeServerResult.errors.length)) {
_flightClientEntryPlugin.injectedClientEntries.forEach((value, key)=>{
clientConfig.entry[key] = value;
});
clientResult = await (0, _compiler).runCompiler(clientConfig, {
runWebpackSpan
});
}
}
result = {
warnings: [].concat(clientResult == null ? void 0 : clientResult.warnings, serverResult == null ? void 0 : serverResult.warnings, edgeServerResult == null ? void 0 : edgeServerResult.warnings).filter(_nonNullable.nonNullable),
errors: [].concat(clientResult == null ? void 0 : clientResult.errors, serverResult == null ? void 0 : serverResult.errors, edgeServerResult == null ? void 0 : edgeServerResult.errors).filter(_nonNullable.nonNullable),
stats: [
clientResult == null ? void 0 : clientResult.stats,
serverResult == null ? void 0 : serverResult.stats,
edgeServerResult == null ? void 0 : edgeServerResult.stats,
]
};
});
result = nextBuildSpan.traceChild("format-webpack-messages").traceFn(()=>(0, _formatWebpackMessages).default(result, true));
telemetryPlugin = (ref = clientConfig.plugins) == null ? void 0 : ref.find(isTelemetryPlugin);
})();
const webpackBuildEnd = process.hrtime(webpackBuildStart);
if (buildSpinner) {
buildSpinner.stopAndPersist();
}
if (result.errors.length > 0) {
// Only keep the first few errors. Others are often indicative
// of the same problem, but confuse the reader with noise.
if (result.errors.length > 5) {
result.errors.length = 5;
}
let error = result.errors.filter(Boolean).join("\n\n");
console.error(_chalk.default.red("Failed to compile.\n"));
if (error.indexOf("private-next-pages") > -1 && error.indexOf("does not contain a default export") > -1) {
const page_name_regex = /'private-next-pages\/(?<page_name>[^']*)'/;
const parsed = page_name_regex.exec(error);
const page_name = parsed && parsed.groups && parsed.groups.page_name;
throw new Error(`webpack build failed: found page without a React Component as default export in pages/${page_name}\n\nSee https://nextjs.org/docs/messages/page-without-valid-component for more info.`);
}
console.error(error);
console.error();
if (error.indexOf("private-next-pages") > -1 || error.indexOf("__next_polyfill__") > -1) {
const err = new Error("webpack config.resolve.alias was incorrectly overridden. https://nextjs.org/docs/messages/invalid-resolve-alias");
err.code = "INVALID_RESOLVE_ALIAS";
throw err;
}
const err = new Error("Build failed because of webpack errors");
err.code = "WEBPACK_ERRORS";
throw err;
} else {
telemetry.record((0, _events).eventBuildCompleted(pagesPaths, {
durationInSeconds: webpackBuildEnd[0]
}));
if (result.warnings.length > 0) {
Log.warn("Compiled with warnings\n");
console.warn(result.warnings.filter(Boolean).join("\n\n"));
console.warn();
} else {
Log.info("Compiled successfully");
}
}
const postCompileSpinner = (0, _spinner).default({
prefixText: `${Log.prefixes.info} Collecting page data`
});
const buildManifestPath = _path.default.join(distDir, _constants1.BUILD_MANIFEST);
const appBuildManifestPath = _path.default.join(distDir, _constants1.APP_BUILD_MANIFEST);
const ssgPages = new Set();
const ssgStaticFallbackPages = new Set();
const ssgBlockingFallbackPages = new Set();
const staticPages = new Set();
const invalidPages = new Set();
const hybridAmpPages = new Set();
const serverPropsPages = new Set();
const additionalSsgPaths = new Map();
const additionalSsgPathsEncoded = new Map();
const pageTraceIncludes = new Map();
const pageTraceExcludes = new Map();
const pageInfos = new Map();
const pagesManifest = JSON.parse(await _fs.promises.readFile(manifestPath, "utf8"));
const buildManifest = JSON.parse(await _fs.promises.readFile(buildManifestPath, "utf8"));
const appBuildManifest = appDir ? JSON.parse(await _fs.promises.readFile(appBuildManifestPath, "utf8")) : undefined;
const timeout = config.staticPageGenerationTimeout || 0;
const sharedPool = config.experimental.sharedPool || false;
const staticWorker = sharedPool ? require.resolve("./worker") : require.resolve("./utils");
let infoPrinted = false;
process.env.NEXT_PHASE = _constants1.PHASE_PRODUCTION_BUILD;
const staticWorkers = new _worker.Worker(staticWorker, {
timeout: timeout * 1000,
onRestart: (method, [arg], attempts)=>{
if (method === "exportPage") {
const { path: pagePath } = arg;
if (attempts >= 3) {
throw new Error(`Static page generation for ${pagePath} is still timing out after 3 attempts. See more info here https://nextjs.org/docs/messages/static-page-generation-timeout`);
}
Log.warn(`Restarted static page generation for ${pagePath} because it took more than ${timeout} seconds`);
} else {
const pagePath = arg;
if (attempts >= 2) {
throw new Error(`Collecting page data for ${pagePath} is still timing out after 2 attempts. See more info here https://nextjs.org/docs/messages/page-data-collection-timeout`);
}
Log.warn(`Restarted collecting page data for ${pagePath} because it took more than ${timeout} seconds`);
}
if (!infoPrinted) {
Log.warn("See more info here https://nextjs.org/docs/messages/static-page-generation-timeout");
infoPrinted = true;
}
},
numWorkers: config.experimental.cpus,
enableWorkerThreads: config.experimental.workerThreads,
exposedMethods: sharedPool ? [
"hasCustomGetInitialProps",
"isPageStatic",
"getNamedExports",
"exportPage",
] : [
"hasCustomGetInitialProps",
"isPageStatic",
"getNamedExports"
]
});
const analysisBegin = process.hrtime();
const staticCheckSpan = nextBuildSpan.traceChild("static-check");
const { customAppGetInitialProps , namedExports , isNextImageImported: isNextImageImported1 , hasSsrAmpPages: hasSsrAmpPages1 , hasNonStaticErrorPage , } = await staticCheckSpan.traceAsyncFn(async ()=>{
const { configFileName , publicRuntimeConfig , serverRuntimeConfig } = config;
const runtimeEnvConfig = {
publicRuntimeConfig,
serverRuntimeConfig
};
const nonStaticErrorPageSpan = staticCheckSpan.traceChild("check-static-error-page");
const errorPageHasCustomGetInitialProps = nonStaticErrorPageSpan.traceAsyncFn(async ()=>hasCustomErrorPage && await staticWorkers.hasCustomGetInitialProps("/_error", distDir, isLikeServerless, runtimeEnvConfig, false));
const errorPageStaticResult = nonStaticErrorPageSpan.traceAsyncFn(async ()=>{
var ref, ref9;
return hasCustomErrorPage && staticWorkers.isPageStatic("/_error", distDir, isLikeServerless, configFileName, runtimeEnvConfig, config.httpAgentOptions, (ref = config.i18n) == null ? void 0 : ref.locales, (ref9 = config.i18n) == null ? void 0 : ref9.defaultLocale);
});
// we don't output _app in serverless mode so use _app export
// from _error instead
const appPageToCheck = isLikeServerless ? "/_error" : "/_app";
const customAppGetInitialPropsPromise = staticWorkers.hasCustomGetInitialProps(appPageToCheck, distDir, isLikeServerless, runtimeEnvConfig, true);
const namedExportsPromise = staticWorkers.getNamedExports(appPageToCheck, distDir, isLikeServerless, runtimeEnvConfig);
// eslint-disable-next-line no-shadow
let isNextImageImported;
// eslint-disable-next-line no-shadow
let hasSsrAmpPages = false;
const computedManifestData = await (0, _utils2).computeFromManifest({
build: buildManifest,
app: appBuildManifest
}, distDir, config.experimental.gzipSize);
await Promise.all(Object.entries(pageKeys).reduce((acc, [key, files])=>{
if (!files) {
return acc;
}
const pageType = key;
for (const page of files){
acc.push({
pageType,
page
});
}
return acc;
}, []).map(({ pageType , page })=>{
const checkPageSpan = staticCheckSpan.traceChild("check-page", {
page
});
return checkPageSpan.traceAsyncFn(async ()=>{
const actualPage = (0, _normalizePagePath).normalizePagePath(page);
const [selfSize, allSize] = await (0, _utils2).getJsPageSizeInKb(pageType, actualPage, distDir, buildManifest, appBuildManifest, config.experimental.gzipSize, computedManifestData);
let isSsg = false;
let isStatic = false;
let isServerComponent = false;
let isHybridAmp = false;
let ssgPageRoutes = null;
const pagePath = pageType === "pages" ? pagesPaths.find((p)=>p.startsWith(actualPage + ".") || p.startsWith(actualPage + "/index.")) : appPaths == null ? void 0 : appPaths.find((p)=>p.startsWith(actualPage + "/page."));
const pageRuntime = pageType === "pages" && pagePath ? (await (0, _getPageStaticInfo).getPageStaticInfo({
pageFilePath: (0, _path).join(pagesDir, pagePath),
nextConfig: config
})).runtime : undefined;
if (hasServerComponents && pagePath) {
if ((0, _utils2).isServerComponentPage(config, pagePath)) {
isServerComponent = true;
}
}
if (// Only calculate page static information if the page is not an
// app page.
pageType !== "app" && !(0, _utils2).isReservedPage(page) && // We currently don't support static optimization in the Edge runtime.
pageRuntime !== _constants.SERVER_RUNTIME.edge) {
try {
let isPageStaticSpan = checkPageSpan.traceChild("is-page-static");
let workerResult = await isPageStaticSpan.traceAsyncFn(()=>{
var ref, ref10;
return staticWorkers.isPageStatic(page, distDir, isLikeServerless, configFileName, runtimeEnvConfig, config.httpAgentOptions, (ref = config.i18n) == null ? void 0 : ref.locales, (ref10 = config.i18n) == null ? void 0 : ref10.defaultLocale, isPageStaticSpan.id);
});
if (config.outputFileTracing) {
pageTraceIncludes.set(page, workerResult.traceIncludes || []);
pageTraceExcludes.set(page, workerResult.traceExcludes || []);
}
if (workerResult.isStatic === false && (workerResult.isHybridAmp || workerResult.isAmpOnly)) {
hasSsrAmpPages = true;
}
if (workerResult.isHybridAmp) {
isHybridAmp = true;
hybridAmpPages.add(page);
}
if (workerResult.isNextImageImported) {
isNextImageImported = true;
}
if (workerResult.hasStaticProps) {
ssgPages.add(page);
isSsg = true;
if (workerResult.prerenderRoutes && workerResult.encodedPrerenderRoutes) {
additionalSsgPaths.set(page, workerResult.prerenderRoutes);
additionalSsgPathsEncoded.set(page, workerResult.encodedPrerenderRoutes);
ssgPageRoutes = workerResult.prerenderRoutes;
}
if (workerResult.prerenderFallback === "blocking") {
ssgBlockingFallbackPages.add(page);
} else if (workerResult.prerenderFallback === true) {
ssgStaticFallbackPages.add(page);
}
} else if (workerResult.hasServerProps) {
serverPropsPages.add(page);
} else if (workerResult.isStatic && !isServerComponent && await customAppGetInitialPropsPromise === false) {
staticPages.add(page);
isStatic = true;
} else if (isServerComponent) {
// This is a static server component page that doesn't have
// gSP or gSSP. We still treat it as a SSG page.
ssgPages.add(page);
isSsg = true;
}
if (hasPages404 && page === "/404") {
if (!workerResult.isStatic && !workerResult.hasStaticProps) {
throw new Error(`\`pages/404\` ${_constants.STATIC_STATUS_PAGE_GET_INITIAL_PROPS_ERROR}`);
}
// we need to ensure the 404 lambda is present since we use
// it when _app has getInitialProps
if (await customAppGetInitialPropsPromise && !workerResult.hasStaticProps) {
staticPages.delete(page);
}
}
if (_constants1.STATIC_STATUS_PAGES.includes(page) && !workerResult.isStatic && !workerResult.hasStaticProps) {
throw new Error(`\`pages${page}\` ${_constants.STATIC_STATUS_PAGE_GET_INITIAL_PROPS_ERROR}`);
}
} catch (err) {
if (!(0, _isError).default(err) || err.message !== "INVALID_DEFAULT_EXPORT") throw err;
invalidPages.add(page);
}
}
pageInfos.set(page, {
size: selfSize,
totalSize: allSize,
static: isStatic,
isSsg,
isHybridAmp,
ssgPageRoutes,
initialRevalidateSeconds: false,
runtime: pageRuntime,
pageDuration: undefined,
ssgPageDurations: undefined
});
});
}));
const errorPageResult = await errorPageStaticResult;
const nonStaticErrorPage = await errorPageHasCustomGetInitialProps || errorPageResult && errorPageResult.hasServerProps;
const returnValue = {
customAppGetInitialProps: await customAppGetInitialPropsPromise,
namedExports: await namedExportsPromise,
isNextImageImported,
hasSsrAmpPages,
hasNonStaticErrorPage: nonStaticErrorPage
};
if (!sharedPool) staticWorkers.end();
return returnValue;
});
if (customAppGetInitialProps) {
console.warn(_chalk.default.bold.yellow(`Warning: `) + _chalk.default.yellow(`You have opted-out of Automatic Static Optimization due to \`getInitialProps\` in \`pages/_app\`. This does not opt-out pages with \`getStaticProps\``));
console.warn("Read more: https://nextjs.org/docs/messages/opt-out-auto-static-optimization\n");
}
if (!hasSsrAmpPages1) {
requiredServerFiles.ignore.push(_path.default.relative(dir, _path.default.join(_path.default.dirname(require.resolve("next/dist/compiled/@ampproject/toolbox-optimizer")), "**/*")));
}
if (config.outputFileTracing) {
const { nodeFileTrace } = require("next/dist/compiled/@vercel/nft");
const includeExcludeSpan = nextBuildSpan.traceChild("apply-include-excludes");
await includeExcludeSpan.traceAsyncFn(async ()=>{
const globOrig = require("next/dist/compiled/glob");
const glob = (pattern)=>{
return new Promise((resolve, reject)=>{
globOrig(pattern, {
cwd: dir
}, (err, files)=>{
if (err) {
return reject(err);
}
resolve(files);
});
});
};
for (let page of pageKeys.pages){
await includeExcludeSpan.traceChild("include-exclude", {
page
}).traceAsyncFn(async ()=>{
const includeGlobs = pageTraceIncludes.get(page);
const excludeGlobs = pageTraceExcludes.get(page);
page = (0, _normalizePagePath).normalizePagePath(page);
if (!(includeGlobs == null ? void 0 : includeGlobs.length) && !(excludeGlobs == null ? void 0 : excludeGlobs.length)) {
return;
}
const traceFile = _path.default.join(distDir, "server/pages", `${page}.js.nft.json`);
const pageDir = _path.default.dirname(traceFile);
const traceContent = JSON.parse(await _fs.promises.readFile(traceFile, "utf8"));
let includes = [];
if (includeGlobs == null ? void 0 : includeGlobs.length) {
for (const includeGlob of includeGlobs){
const results = await glob(includeGlob);
includes.push(...results.map((file)=>{
return _path.default.relative(pageDir, _path.default.join(dir, file));
}));
}
}
const combined = new Set([
...traceContent.files,
...includes
]);
if (excludeGlobs == null ? void 0 : excludeGlobs.length) {
const resolvedGlobs = excludeGlobs.map((exclude)=>_path.default.join(dir, exclude));
combined.forEach((file)=>{
if ((0, _micromatch).isMatch(_path.default.join(pageDir, file), resolvedGlobs)) {
combined.delete(file);
}
});
}
await _fs.promises.writeFile(traceFile, JSON.stringify({
version: traceContent.version,
files: [
...combined
]
}));
});
}
});
// TODO: move this inside of webpack so it can be cached
// between builds. Should only need to be re-run on lockfile change
await nextBuildSpan.traceChild("trace-next-server").traceAsyncFn(async ()=>{
let cacheKey;
// consider all lockFiles in tree in case user accidentally
// has both package-lock.json and yarn.lock
const lockFiles = (await Promise.all([
"package-lock.json",
"yarn.lock",