"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "collectBuildTraces", { enumerable: true, get: function() { return collectBuildTraces; } }); const _trace = require("../trace"); const _nexttraceentrypointsplugin = require("./webpack/plugins/next-trace-entrypoints-plugin"); const _constants = require("../shared/lib/constants"); const _path = /*#__PURE__*/ _interop_require_default(require("path")); const _promises = /*#__PURE__*/ _interop_require_default(require("fs/promises")); const _swc = require("./swc"); const _nonnullable = require("../lib/non-nullable"); const _ciinfo = /*#__PURE__*/ _interop_require_wildcard(require("../telemetry/ci-info")); const _debug = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/debug")); const _micromatch = require("next/dist/compiled/micromatch"); const _requirehook = require("../server/require-hook"); const _nft = require("next/dist/compiled/@vercel/nft"); const _normalizepagepath = require("../shared/lib/page-path/normalize-page-path"); const _apppaths = require("../shared/lib/router/utils/app-paths"); const _iserror = /*#__PURE__*/ _interop_require_default(require("../lib/is-error")); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interop_require_wildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for(var key in obj){ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } const debug = (0, _debug.default)("next:build:build-traces"); async function collectBuildTraces({ dir, config, distDir, pageKeys, pageInfos, staticPages, nextBuildSpan = new _trace.Span({ name: "build" }), hasSsrAmpPages, buildTraceContext, outputFileTracingRoot }) { const startTime = Date.now(); debug("starting build traces"); let turboTasksForTrace; let bindings = await (0, _swc.loadBindings)(); const runTurbotrace = async function() { if (!config.experimental.turbotrace || !buildTraceContext) { return; } if (!(bindings == null ? void 0 : bindings.isWasm) && typeof bindings.turbo.startTrace === "function") { var _config_experimental_turbotrace; let turbotraceOutputPath; let turbotraceFiles; turboTasksForTrace = bindings.turbo.createTurboTasks((((_config_experimental_turbotrace = config.experimental.turbotrace) == null ? void 0 : _config_experimental_turbotrace.memoryLimit) ?? _constants.TURBO_TRACE_DEFAULT_MEMORY_LIMIT) * 1024 * 1024); const { entriesTrace, chunksTrace } = buildTraceContext; if (entriesTrace) { const { appDir: buildTraceContextAppDir, depModArray, entryNameMap, outputPath, action } = entriesTrace; const depModSet = new Set(depModArray); const filesTracedInEntries = await bindings.turbo.startTrace(action, turboTasksForTrace); const { contextDirectory, input: entriesToTrace } = action; // only trace the assets under the appDir // exclude files from node_modules, entries and processed by webpack const filesTracedFromEntries = filesTracedInEntries.map((f)=>_path.default.join(contextDirectory, f)).filter((f)=>!f.includes("/node_modules/") && f.startsWith(buildTraceContextAppDir) && !entriesToTrace.includes(f) && !depModSet.has(f)); if (filesTracedFromEntries.length) { // The turbo trace doesn't provide the traced file type and reason at present // let's write the traced files into the first [entry].nft.json const [[, entryName]] = Array.from(Object.entries(entryNameMap)).filter(([k])=>k.startsWith(buildTraceContextAppDir)); const traceOutputPath = _path.default.join(outputPath, `../${entryName}.js.nft.json`); const traceOutputDir = _path.default.dirname(traceOutputPath); turbotraceOutputPath = traceOutputPath; turbotraceFiles = filesTracedFromEntries.map((file)=>_path.default.relative(traceOutputDir, file)); } } if (chunksTrace) { const { action, outputPath } = chunksTrace; action.input = action.input.filter((f)=>{ const outputPagesPath = _path.default.join(outputPath, "..", "pages"); return !f.startsWith(outputPagesPath) || !staticPages.includes(// strip `outputPagesPath` and file ext from absolute f.substring(outputPagesPath.length, f.length - 3)); }); await bindings.turbo.startTrace(action, turboTasksForTrace); if (turbotraceOutputPath && turbotraceFiles) { const existedNftFile = await _promises.default.readFile(turbotraceOutputPath, "utf8").then((existedContent)=>JSON.parse(existedContent)).catch(()=>({ version: _constants.TRACE_OUTPUT_VERSION, files: [] })); existedNftFile.files.push(...turbotraceFiles); const filesSet = new Set(existedNftFile.files); existedNftFile.files = [ ...filesSet ]; await _promises.default.writeFile(turbotraceOutputPath, JSON.stringify(existedNftFile), "utf8"); } } } }; const { outputFileTracingIncludes = {}, outputFileTracingExcludes = {} } = config.experimental; const excludeGlobKeys = Object.keys(outputFileTracingExcludes); await nextBuildSpan.traceChild("node-file-trace-build").traceAsyncFn(async ()=>{ var _config_experimental_turbotrace, _config_experimental; const nextServerTraceOutput = _path.default.join(distDir, "next-server.js.nft.json"); const nextMinimalTraceOutput = _path.default.join(distDir, "next-minimal-server.js.nft.json"); const root = ((_config_experimental = config.experimental) == null ? void 0 : (_config_experimental_turbotrace = _config_experimental.turbotrace) == null ? void 0 : _config_experimental_turbotrace.contextDirectory) ?? outputFileTracingRoot; // Under standalone mode, we need to trace the extra IPC server and // worker files. const isStandalone = config.output === "standalone"; const nextServerEntry = require.resolve("next/dist/server/next-server"); const sharedEntriesSet = [ ...config.experimental.turbotrace ? [] : Object.keys(_requirehook.defaultOverrides).map((value)=>require.resolve(value, { paths: [ require.resolve("next/dist/server/require-hook") ] })), require.resolve("next/dist/compiled/next-server/app-page.runtime.prod"), require.resolve("next/dist/compiled/next-server/app-route.runtime.prod"), require.resolve("next/dist/compiled/next-server/pages.runtime.prod"), require.resolve("next/dist/compiled/next-server/pages-api.runtime.prod") ]; const { incrementalCacheHandlerPath } = config.experimental; // ensure we trace any dependencies needed for custom // incremental cache handler if (incrementalCacheHandlerPath) { sharedEntriesSet.push(require.resolve(_path.default.isAbsolute(incrementalCacheHandlerPath) ? incrementalCacheHandlerPath : _path.default.join(dir, incrementalCacheHandlerPath))); } const serverEntries = [ ...sharedEntriesSet, ...isStandalone ? [ require.resolve("next/dist/server/lib/start-server"), require.resolve("next/dist/server/next"), require.resolve("next/dist/server/require-hook") ] : [], require.resolve("next/dist/server/next-server") ].filter(Boolean); const minimalServerEntries = [ ...sharedEntriesSet, require.resolve("next/dist/compiled/next-server/server.runtime.prod") ].filter(Boolean); const additionalIgnores = new Set(); for (const glob of excludeGlobKeys){ if ((0, _micromatch.isMatch)("next-server", glob)) { outputFileTracingExcludes[glob].forEach((exclude)=>{ additionalIgnores.add(exclude); }); } } const serverIgnores = [ "**/*.d.ts", "**/*.map", isStandalone ? null : "**/next/dist/compiled/jest-worker/**/*", "**/next/dist/compiled/webpack/(bundle4|bundle5).js", "**/node_modules/webpack5/**/*", "**/next/dist/server/lib/squoosh/**/*.wasm", "**/next/dist/server/lib/route-resolver*", "**/next/dist/pages/**/*", ..._ciinfo.hasNextSupport ? [ // only ignore image-optimizer code when // this is being handled outside of next-server "**/next/dist/server/image-optimizer.js", "**/node_modules/sharp/**/*" ] : [], ...!hasSsrAmpPages ? [ "**/next/dist/compiled/@ampproject/toolbox-optimizer/**/*" ] : [], ...additionalIgnores, ...isStandalone ? [] : _nexttraceentrypointsplugin.TRACE_IGNORES, ...config.experimental.outputFileTracingIgnores || [] ].filter(_nonnullable.nonNullable); const serverIgnoreFn = (pathname)=>{ if (_path.default.isAbsolute(pathname) && !pathname.startsWith(root)) { return true; } return (0, _micromatch.isMatch)(pathname, serverIgnores, { contains: true, dot: true }); }; const traceContext = _path.default.join(nextServerEntry, "..", ".."); const serverTracedFiles = new Set(); const minimalServerTracedFiles = new Set(); function addToTracedFiles(base, file, dest) { dest.add(_path.default.relative(distDir, _path.default.join(base, file)).replace(/\\/g, "/")); } if (isStandalone) { addToTracedFiles("", require.resolve("next/dist/compiled/jest-worker/processChild"), serverTracedFiles); addToTracedFiles("", require.resolve("next/dist/compiled/jest-worker/threadChild"), serverTracedFiles); } if (config.experimental.turbotrace) { await runTurbotrace(); const startTrace = bindings.turbo.startTrace; const makeTrace = async (entries)=>{ var _config_experimental_turbotrace, _config_experimental_turbotrace1, _config_experimental_turbotrace2, _config_experimental_turbotrace3; return startTrace({ action: "print", input: entries, contextDirectory: traceContext, logLevel: (_config_experimental_turbotrace = config.experimental.turbotrace) == null ? void 0 : _config_experimental_turbotrace.logLevel, processCwd: (_config_experimental_turbotrace1 = config.experimental.turbotrace) == null ? void 0 : _config_experimental_turbotrace1.processCwd, logDetail: (_config_experimental_turbotrace2 = config.experimental.turbotrace) == null ? void 0 : _config_experimental_turbotrace2.logDetail, showAll: (_config_experimental_turbotrace3 = config.experimental.turbotrace) == null ? void 0 : _config_experimental_turbotrace3.logAll }, turboTasksForTrace); }; // turbotrace does not handle concurrent tracing const vanillaFiles = await makeTrace(serverEntries); const minimalFiles = await makeTrace(minimalServerEntries); for (const [set, files] of [ [ serverTracedFiles, vanillaFiles ], [ minimalServerTracedFiles, minimalFiles ] ]){ for (const file of files){ if (!serverIgnoreFn(_path.default.join(traceContext, file))) { addToTracedFiles(traceContext, file, set); } } } } else { var _buildTraceContext_chunksTrace; const chunksToTrace = [ ...(buildTraceContext == null ? void 0 : (_buildTraceContext_chunksTrace = buildTraceContext.chunksTrace) == null ? void 0 : _buildTraceContext_chunksTrace.action.input) || [], ...serverEntries, ...minimalServerEntries ]; const result = await (0, _nft.nodeFileTrace)(chunksToTrace, { base: outputFileTracingRoot, processCwd: dir, mixedModules: true, async readFile (p) { try { return await _promises.default.readFile(p, "utf8"); } catch (e) { if ((0, _iserror.default)(e) && (e.code === "ENOENT" || e.code === "EISDIR")) { // handle temporary internal webpack files if (p.match(/static[/\\]media/)) { return ""; } return null; } throw e; } }, async readlink (p) { try { return await _promises.default.readlink(p); } catch (e) { if ((0, _iserror.default)(e) && (e.code === "EINVAL" || e.code === "ENOENT" || e.code === "UNKNOWN")) { return null; } throw e; } }, async stat (p) { try { return await _promises.default.stat(p); } catch (e) { if ((0, _iserror.default)(e) && (e.code === "ENOENT" || e.code === "ENOTDIR")) { return null; } throw e; } } }); const reasons = result.reasons; const fileList = result.fileList; for (const file of result.esmFileList){ fileList.add(file); } const parentFilesMap = (0, _nexttraceentrypointsplugin.getFilesMapFromReasons)(fileList, reasons); for (const [entries, tracedFiles] of [ [ serverEntries, serverTracedFiles ], [ minimalServerEntries, minimalServerTracedFiles ] ]){ for (const file of entries){ const curFiles = parentFilesMap.get(_path.default.relative(outputFileTracingRoot, file)); tracedFiles.add(_path.default.relative(distDir, file).replace(/\\/g, "/")); for (const curFile of curFiles || []){ const filePath = _path.default.join(outputFileTracingRoot, curFile); if (!serverIgnoreFn(filePath)) { tracedFiles.add(_path.default.relative(distDir, filePath).replace(/\\/g, "/")); } } } } const { entryNameFilesMap } = (buildTraceContext == null ? void 0 : buildTraceContext.chunksTrace) || {}; await Promise.all([ ...entryNameFilesMap ? Object.entries(entryNameFilesMap) : new Map() ].map(async ([entryName, entryNameFiles])=>{ const isApp = entryName.startsWith("app/"); const isPages = entryName.startsWith("pages/"); let route = entryName; if (isApp) { route = (0, _apppaths.normalizeAppPath)(route.substring("app".length)); } if (isPages) { route = (0, _normalizepagepath.normalizePagePath)(route.substring("pages".length)); } // we don't need to trace for automatically statically optimized // pages as they don't have server bundles if (staticPages.includes(route)) { return; } const entryOutputPath = _path.default.join(distDir, "server", `${entryName}.js`); const traceOutputPath = `${entryOutputPath}.nft.json`; const existingTrace = JSON.parse(await _promises.default.readFile(traceOutputPath, "utf8")); const traceOutputDir = _path.default.dirname(traceOutputPath); const curTracedFiles = new Set(); for (const file of [ ...entryNameFiles, entryOutputPath ]){ const curFiles = parentFilesMap.get(_path.default.relative(outputFileTracingRoot, file)); for (const curFile of curFiles || []){ curTracedFiles.add(_path.default.relative(traceOutputDir, _path.default.join(outputFileTracingRoot, curFile)).replace(/\\/g, "/")); } } for (const file of existingTrace.files || []){ curTracedFiles.add(file); } await _promises.default.writeFile(traceOutputPath, JSON.stringify({ ...existingTrace, files: [ ...curTracedFiles ].sort() })); })); } const moduleTypes = [ "app-page", "pages" ]; for (const type of moduleTypes){ const modulePath = require.resolve(`next/dist/server/future/route-modules/${type}/module.compiled`); const relativeModulePath = _path.default.relative(root, modulePath); const contextDir = _path.default.join(_path.default.dirname(modulePath), "vendored", "contexts"); for (const item of (await _promises.default.readdir(contextDir))){ const itemPath = _path.default.relative(root, _path.default.join(contextDir, item)); addToTracedFiles(root, itemPath, serverTracedFiles); addToTracedFiles(root, itemPath, minimalServerTracedFiles); } addToTracedFiles(root, relativeModulePath, serverTracedFiles); addToTracedFiles(root, relativeModulePath, minimalServerTracedFiles); } await Promise.all([ _promises.default.writeFile(nextServerTraceOutput, JSON.stringify({ version: 1, files: Array.from(serverTracedFiles) })), _promises.default.writeFile(nextMinimalTraceOutput, JSON.stringify({ version: 1, files: Array.from(minimalServerTracedFiles) })) ]); }); const includeExcludeSpan = nextBuildSpan.traceChild("apply-include-excludes"); const resolvedTraceIncludes = new Map(); const includeGlobKeys = Object.keys(outputFileTracingIncludes); await includeExcludeSpan.traceAsyncFn(async ()=>{ const globOrig = require("next/dist/compiled/glob"); const glob = (pattern)=>{ return new Promise((resolve, reject)=>{ globOrig(pattern, { cwd: dir, nodir: true, dot: true }, (err, files)=>{ if (err) { return reject(err); } resolve(files); }); }); }; for (let page of pageKeys.pages){ // edge routes have no trace files const [, pageInfo] = pageInfos.find((item)=>item[0] === page) || []; if ((pageInfo == null ? void 0 : pageInfo.runtime) === "edge") { continue; } const combinedIncludes = new Set(); const combinedExcludes = new Set(); page = (0, _normalizepagepath.normalizePagePath)(page); for (const curGlob of includeGlobKeys){ if ((0, _micromatch.isMatch)(page, [ curGlob ], { dot: true, contains: true })) { for (const include of outputFileTracingIncludes[curGlob]){ combinedIncludes.add(include.replace(/\\/g, "/")); } } } for (const curGlob of excludeGlobKeys){ if ((0, _micromatch.isMatch)(page, [ curGlob ], { dot: true, contains: true })) { for (const exclude of outputFileTracingExcludes[curGlob]){ combinedExcludes.add(exclude); } } } if (!(combinedIncludes == null ? void 0 : combinedIncludes.size) && !(combinedExcludes == null ? void 0 : combinedExcludes.size)) { continue; } const traceFile = _path.default.join(distDir, "server/pages", `${page}.js.nft.json`); const pageDir = _path.default.dirname(traceFile); const traceContent = JSON.parse(await _promises.default.readFile(traceFile, "utf8")); const includes = []; if (combinedIncludes == null ? void 0 : combinedIncludes.size) { await Promise.all([ ...combinedIncludes ].map(async (includeGlob)=>{ const results = await glob(includeGlob); const resolvedInclude = resolvedTraceIncludes.get(includeGlob) || [ ...results.map((file)=>{ return _path.default.relative(pageDir, _path.default.join(dir, file)); }) ]; includes.push(...resolvedInclude); resolvedTraceIncludes.set(includeGlob, resolvedInclude); })); } const combined = new Set([ ...traceContent.files, ...includes ]); if (combinedExcludes == null ? void 0 : combinedExcludes.size) { const resolvedGlobs = [ ...combinedExcludes ].map((exclude)=>_path.default.join(dir, exclude)); combined.forEach((file)=>{ if ((0, _micromatch.isMatch)(_path.default.join(pageDir, file), resolvedGlobs, { dot: true, contains: true })) { combined.delete(file); } }); } await _promises.default.writeFile(traceFile, JSON.stringify({ version: traceContent.version, files: [ ...combined ] })); } }); debug(`finished build tracing ${Date.now() - startTime}ms`); } //# sourceMappingURL=collect-build-traces.js.map