From 1d17d183c62e0ce85ef9359d9ae26359f998a80b Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 2 Oct 2023 00:03:57 -0700 Subject: [PATCH 1/2] Update parallelizing tasks with webpackBuildWorker config --- packages/next/src/build/build-context.ts | 7 -- .../next/src/build/collect-build-traces.ts | 32 +++++--- packages/next/src/build/index.ts | 78 +++++++++++++++---- packages/next/src/build/webpack-build/impl.ts | 29 +------ .../next/src/build/webpack-build/index.ts | 70 ++++++++++------- packages/next/src/build/webpack-config.ts | 1 + .../plugins/next-trace-entrypoints-plugin.ts | 8 +- .../webpack/plugins/pages-manifest-plugin.ts | 67 ++++++++++------ packages/next/src/lib/worker.ts | 2 +- 9 files changed, 177 insertions(+), 117 deletions(-) diff --git a/packages/next/src/build/build-context.ts b/packages/next/src/build/build-context.ts index 0c31b8e0d008d..393f0ed17e464 100644 --- a/packages/next/src/build/build-context.ts +++ b/packages/next/src/build/build-context.ts @@ -5,7 +5,6 @@ import type { __ApiPreviewProps } from '../server/api-utils' import type { NextConfigComplete } from '../server/config-shared' import type { Span } from '../trace' import type getBaseWebpackConfig from './webpack-config' -import type { PagesManifest } from './webpack/plugins/pages-manifest-plugin' import type { TelemetryPlugin } from './webpack/plugins/telemetry-plugin' // A layer for storing data that is used by plugins to communicate with each @@ -48,12 +47,6 @@ export function getPluginState() { export const NextBuildContext: Partial<{ compilerIdx?: number pluginState: Record - serializedPagesManifestEntries: { - edgeServerPages?: PagesManifest - nodeServerPages?: PagesManifest - edgeServerAppPaths?: PagesManifest - nodeServerAppPaths?: PagesManifest - } // core fields dir: string buildId: string diff --git a/packages/next/src/build/collect-build-traces.ts b/packages/next/src/build/collect-build-traces.ts index 39956374130da..e64fd17834698 100644 --- a/packages/next/src/build/collect-build-traces.ts +++ b/packages/next/src/build/collect-build-traces.ts @@ -1,4 +1,4 @@ -import type { Span } from '../trace' +import { Span } from '../trace' import type { NextConfigComplete } from '../server/config-shared' import { @@ -18,12 +18,15 @@ import { PageInfo } from './utils' import { loadBindings } from './swc' import { nonNullable } from '../lib/non-nullable' import * as ciEnvironment from '../telemetry/ci-info' +import debugOriginal from 'next/dist/compiled/debug' import { isMatch } from 'next/dist/compiled/micromatch' import { defaultOverrides } from '../server/require-hook' import { nodeFileTrace } from 'next/dist/compiled/@vercel/nft' import { normalizePagePath } from '../shared/lib/page-path/normalize-page-path' import { normalizeAppPath } from '../shared/lib/router/utils/app-paths' +const debug = debugOriginal('next:build:build-traces') + export async function collectBuildTraces({ dir, config, @@ -31,7 +34,7 @@ export async function collectBuildTraces({ pageKeys, pageInfos, staticPages, - nextBuildSpan, + nextBuildSpan = new Span({ name: 'build' }), hasSsrAmpPages, buildTraceContext, outputFileTracingRoot, @@ -42,14 +45,16 @@ export async function collectBuildTraces({ app?: string[] pages: string[] } - staticPages: Set + staticPages: string[] hasSsrAmpPages: boolean outputFileTracingRoot: string - pageInfos: Map - nextBuildSpan: Span + pageInfos: [string, PageInfo][] + nextBuildSpan?: Span config: NextConfigComplete buildTraceContext?: BuildTraceContext }) { + const startTime = Date.now() + debug('starting build traces') let turboTasksForTrace: unknown let bindings = await loadBindings() @@ -99,7 +104,7 @@ export async function collectBuildTraces({ // 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<[string, string]>( - entryNameMap.entries() + Object.entries(entryNameMap) ).filter(([k]) => k.startsWith(buildTraceContextAppDir)) const traceOutputPath = path.join( outputPath, @@ -119,7 +124,7 @@ export async function collectBuildTraces({ const outputPagesPath = path.join(outputPath, '..', 'pages') return ( !f.startsWith(outputPagesPath) || - !staticPages.has( + !staticPages.includes( // strip `outputPagesPath` and file ext from absolute f.substring(outputPagesPath.length, f.length - 3) ) @@ -369,10 +374,13 @@ export async function collectBuildTraces({ } } + const { entryNameFilesMap } = buildTraceContext?.chunksTrace || {} + await Promise.all( [ - ...(buildTraceContext?.chunksTrace?.entryNameFilesMap.entries() || - new Map()), + ...(entryNameFilesMap + ? Object.entries(entryNameFilesMap) + : new Map()), ].map(async ([entryName, entryNameFiles]) => { const isApp = entryName.startsWith('app/') const isPages = entryName.startsWith('pages/') @@ -387,7 +395,7 @@ export async function collectBuildTraces({ // we don't need to trace for automatically statically optimized // pages as they don't have server bundles - if (staticPages.has(route)) { + if (staticPages.includes(route)) { return } const entryOutputPath = path.join( @@ -504,7 +512,7 @@ export async function collectBuildTraces({ for (let page of pageKeys.pages) { // edge routes have no trace files - const pageInfo = pageInfos.get(page) + const [, pageInfo] = pageInfos.find((item) => item[0] === page) || [] if (pageInfo?.runtime === 'edge') { continue } @@ -584,4 +592,6 @@ export async function collectBuildTraces({ ) } }) + + debug(`finished build tracing ${Date.now() - startTime}ms`) } diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index 72f9c7f5ae160..e1ccccce957e0 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -1018,20 +1018,72 @@ export default async function build( return { duration, buildTraceContext: null } } let buildTraceContext: undefined | BuildTraceContext + let buildTracesPromise: Promise | undefined = undefined if (!isGenerate) { - const { duration: webpackBuildDuration, ...rest } = turboNextBuild - ? await turbopackBuild() - : await webpackBuild() + if (isCompile && config.experimental.webpackBuildWorker) { + let durationInSeconds = 0 + + await webpackBuild(['server']).then((res) => { + buildTraceContext = res.buildTraceContext + durationInSeconds += res.duration + const buildTraceWorker = new Worker( + require.resolve('./collect-build-traces'), + { + numWorkers: 1, + exposedMethods: ['collectBuildTraces'], + } + ) as Worker & typeof import('./collect-build-traces') - buildTraceContext = rest.buildTraceContext + buildTracesPromise = buildTraceWorker + .collectBuildTraces({ + dir, + config, + distDir, + pageKeys, + pageInfos: [], + staticPages: [], + hasSsrAmpPages: false, + buildTraceContext, + outputFileTracingRoot, + }) + .catch((err) => { + console.error(err) + process.exit(1) + }) + }) - telemetry.record( - eventBuildCompleted(pagesPaths, { - durationInSeconds: webpackBuildDuration, - totalAppPagesCount, + await webpackBuild(['edge-server']).then((res) => { + durationInSeconds += res.duration }) - ) + + await webpackBuild(['client']).then((res) => { + durationInSeconds += res.duration + }) + + buildSpinner?.stopAndPersist() + Log.event('Compiled successfully') + + telemetry.record( + eventBuildCompleted(pagesPaths, { + durationInSeconds, + totalAppPagesCount, + }) + ) + } else { + const { duration: webpackBuildDuration, ...rest } = turboNextBuild + ? await turbopackBuild() + : await webpackBuild() + + buildTraceContext = rest.buildTraceContext + + telemetry.record( + eventBuildCompleted(pagesPaths, { + durationInSeconds: webpackBuildDuration, + totalAppPagesCount, + }) + ) + } } // For app directory, we run type checking after build. @@ -1761,16 +1813,14 @@ export default async function build( ) } - let buildTracesPromise: Promise | undefined = undefined - - if (!isGenerate && config.outputFileTracing) { + if (!isGenerate && config.outputFileTracing && !buildTracesPromise) { buildTracesPromise = collectBuildTraces({ dir, config, distDir, pageKeys, - pageInfos, - staticPages, + pageInfos: Object.entries(pageInfos), + staticPages: [...staticPages], nextBuildSpan, hasSsrAmpPages, buildTraceContext, diff --git a/packages/next/src/build/webpack-build/impl.ts b/packages/next/src/build/webpack-build/impl.ts index 4d8bcb94ad05f..d0c686c2c3d74 100644 --- a/packages/next/src/build/webpack-build/impl.ts +++ b/packages/next/src/build/webpack-build/impl.ts @@ -28,7 +28,6 @@ import { TraceEntryPointsPlugin, } from '../webpack/plugins/next-trace-entrypoints-plugin' import { UnwrapPromise } from '../../lib/coalesced-function' -import * as pagesPluginModule from '../webpack/plugins/pages-manifest-plugin' import origDebug from 'next/dist/compiled/debug' @@ -62,7 +61,6 @@ export async function webpackBuildImpl( duration: number pluginState: any buildTraceContext?: BuildTraceContext - serializedPagesManifestEntries?: (typeof NextBuildContext)['serializedPagesManifestEntries'] }> { let result: CompilerResult | null = { warnings: [], @@ -327,12 +325,6 @@ export async function webpackBuildImpl( duration: webpackBuildEnd[0], buildTraceContext: traceEntryPointsPlugin?.buildTraceContext, pluginState: getPluginState(), - serializedPagesManifestEntries: { - edgeServerPages: pagesPluginModule.edgeServerPages, - edgeServerAppPaths: pagesPluginModule.edgeServerAppPaths, - nodeServerPages: pagesPluginModule.nodeServerPages, - nodeServerAppPaths: pagesPluginModule.nodeServerAppPaths, - }, } } } @@ -348,16 +340,6 @@ export async function workerMain(workerData: { // Resume plugin state resumePluginState(NextBuildContext.pluginState) - // restore module scope maps for flight plugins - const { serializedPagesManifestEntries } = NextBuildContext - - for (const key of Object.keys(serializedPagesManifestEntries || {})) { - Object.assign( - (pagesPluginModule as any)[key], - (serializedPagesManifestEntries as any)?.[key] - ) - } - /// load the config because it's not serializable NextBuildContext.config = await loadConfig( PHASE_PRODUCTION_BUILD, @@ -373,17 +355,12 @@ export async function workerMain(workerData: { result.buildTraceContext!.entriesTrace!.depModArray = depModArray } if (entryNameMap) { - const entryEntries = Array.from(entryNameMap?.entries() ?? []) - // @ts-expect-error - result.buildTraceContext.entriesTrace.entryNameMap = entryEntries + const entryEntries = entryNameMap + result.buildTraceContext!.entriesTrace!.entryNameMap = entryEntries } } if (chunksTrace?.entryNameFilesMap) { - const entryNameFilesMap = Array.from( - chunksTrace.entryNameFilesMap.entries() ?? [] - ) - - // @ts-expect-error + const entryNameFilesMap = chunksTrace.entryNameFilesMap result.buildTraceContext!.chunksTrace!.entryNameFilesMap = entryNameFilesMap } return result diff --git a/packages/next/src/build/webpack-build/index.ts b/packages/next/src/build/webpack-build/index.ts index 9aefee1b6ec54..9d5855f8c5072 100644 --- a/packages/next/src/build/webpack-build/index.ts +++ b/packages/next/src/build/webpack-build/index.ts @@ -9,7 +9,29 @@ import path from 'path' const debug = origDebug('next:build:webpack-build') -async function webpackBuildWithWorker() { +const ORDERED_COMPILER_NAMES = [ + 'server', + 'edge-server', + 'client', +] as (keyof typeof COMPILER_INDEXES)[] + +let pluginState: Record = {} + +function deepMerge(target: any, source: any) { + const result = { ...target, ...source } + for (const key of Object.keys(result)) { + result[key] = Array.isArray(target[key]) + ? (target[key] = [...target[key], ...(source[key] || [])]) + : typeof target[key] == 'object' && typeof source[key] == 'object' + ? deepMerge(target[key], source[key]) + : structuredClone(result[key]) + } + return result +} + +async function webpackBuildWithWorker( + compilerNames: typeof ORDERED_COMPILER_NAMES = ORDERED_COMPILER_NAMES +) { const { config, telemetryPlugin, @@ -18,6 +40,8 @@ async function webpackBuildWithWorker() { ...prunedBuildContext } = NextBuildContext + prunedBuildContext.pluginState = pluginState + const getWorker = (compilerName: string) => { const _worker = new Worker(path.join(__dirname, 'impl.js'), { exposedMethods: ['workerMain'], @@ -37,7 +61,7 @@ async function webpackBuildWithWorker() { _child: ChildProcess }[]) { worker._child.on('exit', (code, signal) => { - if (code || signal) { + if (code || (signal && signal !== 'SIGINT')) { console.error( `Compiler ${compilerName} unexpectedly exited with code: ${code} and signal: ${signal}` ) @@ -52,14 +76,8 @@ async function webpackBuildWithWorker() { duration: 0, buildTraceContext: {} as BuildTraceContext, } - // order matters here - const ORDERED_COMPILER_NAMES = [ - 'server', - 'edge-server', - 'client', - ] as (keyof typeof COMPILER_INDEXES)[] - - for (const compilerName of ORDERED_COMPILER_NAMES) { + + for (const compilerName of compilerNames) { const worker = getWorker(compilerName) const curResult = await worker.workerMain({ @@ -70,18 +88,8 @@ async function webpackBuildWithWorker() { await worker.end() // Update plugin state - prunedBuildContext.pluginState = curResult.pluginState - - prunedBuildContext.serializedPagesManifestEntries = { - edgeServerAppPaths: - curResult.serializedPagesManifestEntries?.edgeServerAppPaths, - edgeServerPages: - curResult.serializedPagesManifestEntries?.edgeServerPages, - nodeServerAppPaths: - curResult.serializedPagesManifestEntries?.nodeServerAppPaths, - nodeServerPages: - curResult.serializedPagesManifestEntries?.nodeServerPages, - } + pluginState = deepMerge(pluginState, curResult.pluginState) + prunedBuildContext.pluginState = pluginState combinedResult.duration += curResult.duration @@ -91,9 +99,8 @@ async function webpackBuildWithWorker() { if (entryNameMap) { combinedResult.buildTraceContext.entriesTrace = curResult.buildTraceContext.entriesTrace - combinedResult.buildTraceContext.entriesTrace!.entryNameMap = new Map( + combinedResult.buildTraceContext.entriesTrace!.entryNameMap = entryNameMap - ) } if (curResult.buildTraceContext?.chunksTrace) { @@ -104,23 +111,28 @@ async function webpackBuildWithWorker() { curResult.buildTraceContext.chunksTrace! combinedResult.buildTraceContext.chunksTrace!.entryNameFilesMap = - new Map(entryNameFilesMap) + entryNameFilesMap } } } } - buildSpinner?.stopAndPersist() - Log.event('Compiled successfully') + + if (compilerNames.length === 3) { + buildSpinner?.stopAndPersist() + Log.event('Compiled successfully') + } return combinedResult } -export async function webpackBuild() { +export async function webpackBuild( + compilerNames?: typeof ORDERED_COMPILER_NAMES +) { const config = NextBuildContext.config! if (config.experimental.webpackBuildWorker) { debug('using separate compiler workers') - return await webpackBuildWithWorker() + return await webpackBuildWithWorker(compilerNames) } else { debug('building all compilers in same process') const webpackBuildImpl = require('./impl').webpackBuildImpl diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index e67191f0cf1b1..7f8aff4f2be44 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -2036,6 +2036,7 @@ export default async function getBaseWebpackConfig( isNodeOrEdgeCompilation && new PagesManifestPlugin({ dev, + distDir, isEdgeRuntime: isEdgeServer, appDirEnabled: hasAppDir, }), diff --git a/packages/next/src/build/webpack/plugins/next-trace-entrypoints-plugin.ts b/packages/next/src/build/webpack/plugins/next-trace-entrypoints-plugin.ts index a4fec7c6ec883..7ce133dbb774d 100644 --- a/packages/next/src/build/webpack/plugins/next-trace-entrypoints-plugin.ts +++ b/packages/next/src/build/webpack/plugins/next-trace-entrypoints-plugin.ts @@ -120,12 +120,12 @@ export interface BuildTraceContext { appDir: string outputPath: string depModArray: string[] - entryNameMap: Map + entryNameMap: Record } chunksTrace?: { action: TurbotraceAction outputPath: string - entryNameFilesMap: Map> + entryNameFilesMap: Record> } } @@ -224,7 +224,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance { logLevel: this.turbotrace?.logLevel, }, outputPath, - entryNameFilesMap, + entryNameFilesMap: Object.fromEntries(entryNameFilesMap), } for (const [entrypoint, entryFiles] of entryFilesMap) { @@ -436,7 +436,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance { }, appDir: this.rootDir, depModArray: Array.from(depModMap.keys()), - entryNameMap, + entryNameMap: Object.fromEntries(entryNameMap), outputPath: compilation.outputOptions.path!, } diff --git a/packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts b/packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts index 3fd9d386129b8..69f1cfdd18f0d 100644 --- a/packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts +++ b/packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts @@ -1,4 +1,6 @@ -import { webpack, sources } from 'next/dist/compiled/webpack/webpack' +import path from 'path' +import fs from 'fs/promises' +import { webpack } from 'next/dist/compiled/webpack/webpack' import { PAGES_MANIFEST, APP_PATHS_MANIFEST, @@ -20,24 +22,28 @@ export default class PagesManifestPlugin implements webpack.WebpackPluginInstance { dev: boolean + distDir: string isEdgeRuntime: boolean appDirEnabled: boolean constructor({ dev, + distDir, isEdgeRuntime, appDirEnabled, }: { dev: boolean + distDir: string isEdgeRuntime: boolean appDirEnabled: boolean }) { this.dev = dev + this.distDir = distDir this.isEdgeRuntime = isEdgeRuntime this.appDirEnabled = appDirEnabled } - createAssets(compilation: any, assets: any) { + async createAssets(compilation: any) { const entrypoints = compilation.entrypoints const pages: PagesManifest = {} const appPaths: PagesManifest = {} @@ -92,45 +98,56 @@ export default class PagesManifestPlugin nodeServerAppPaths = appPaths } - assets[ - `${!this.dev && !this.isEdgeRuntime ? '../' : ''}` + PAGES_MANIFEST - ] = new sources.RawSource( - JSON.stringify( - { - ...edgeServerPages, - ...nodeServerPages, - }, - null, - 2 - ) - ) - - if (this.appDirEnabled) { - assets[ - `${!this.dev && !this.isEdgeRuntime ? '../' : ''}` + APP_PATHS_MANIFEST - ] = new sources.RawSource( + // handle parallel compilers writing to the same + // manifest path by merging existing manifest with new + const writeMergedManifest = async ( + manifestPath: string, + entries: Record + ) => { + await fs.mkdir(path.dirname(manifestPath), { recursive: true }) + await fs.writeFile( + manifestPath, JSON.stringify( { - ...edgeServerAppPaths, - ...nodeServerAppPaths, + ...(await fs + .readFile(manifestPath, 'utf8') + .then((res) => JSON.parse(res)) + .catch(() => ({}))), + ...entries, }, null, 2 ) ) } + + const pagesManifestPath = path.join(this.distDir, 'server', PAGES_MANIFEST) + await writeMergedManifest(pagesManifestPath, { + ...edgeServerPages, + ...nodeServerPages, + }) + + if (this.appDirEnabled) { + const appPathsManifestPath = path.join( + this.distDir, + 'server', + APP_PATHS_MANIFEST + ) + await writeMergedManifest(appPathsManifestPath, { + ...edgeServerAppPaths, + ...nodeServerAppPaths, + }) + } } apply(compiler: webpack.Compiler): void { compiler.hooks.make.tap('NextJsPagesManifest', (compilation) => { - compilation.hooks.processAssets.tap( + compilation.hooks.processAssets.tapPromise( { name: 'NextJsPagesManifest', stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS, }, - (assets: any) => { - this.createAssets(compilation, assets) - } + () => this.createAssets(compilation) ) }) } diff --git a/packages/next/src/lib/worker.ts b/packages/next/src/lib/worker.ts index 5beecff8c70ff..65ba035f2c6b2 100644 --- a/packages/next/src/lib/worker.ts +++ b/packages/next/src/lib/worker.ts @@ -69,7 +69,7 @@ export class Worker { }[]) { worker._child?.on('exit', (code, signal) => { // log unexpected exit if .end() wasn't called - if ((code || signal) && this._worker) { + if ((code || (signal && signal !== 'SIGINT')) && this._worker) { console.error( `Static worker unexpectedly exited with code: ${code} and signal: ${signal}` ) From 843a3e63580a304c3dd55fa8b690266ae3f35b5d Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 2 Oct 2023 11:56:10 -0700 Subject: [PATCH 2/2] fix pages-manifest in dev --- packages/next/src/build/webpack-config.ts | 4 +- .../webpack/plugins/pages-manifest-plugin.ts | 69 ++++++++++++++----- 2 files changed, 54 insertions(+), 19 deletions(-) diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index 7f8aff4f2be44..a6273cfa42c82 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -2036,9 +2036,9 @@ export default async function getBaseWebpackConfig( isNodeOrEdgeCompilation && new PagesManifestPlugin({ dev, - distDir, - isEdgeRuntime: isEdgeServer, appDirEnabled: hasAppDir, + isEdgeRuntime: isEdgeServer, + distDir: !dev ? distDir : undefined, }), // MiddlewarePlugin should be after DefinePlugin so NEXT_PUBLIC_* // replacement is done before its process.env.* handling diff --git a/packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts b/packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts index 69f1cfdd18f0d..1374395ffa399 100644 --- a/packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts +++ b/packages/next/src/build/webpack/plugins/pages-manifest-plugin.ts @@ -1,6 +1,6 @@ import path from 'path' import fs from 'fs/promises' -import { webpack } from 'next/dist/compiled/webpack/webpack' +import { webpack, sources } from 'next/dist/compiled/webpack/webpack' import { PAGES_MANIFEST, APP_PATHS_MANIFEST, @@ -22,7 +22,7 @@ export default class PagesManifestPlugin implements webpack.WebpackPluginInstance { dev: boolean - distDir: string + distDir?: string isEdgeRuntime: boolean appDirEnabled: boolean @@ -33,7 +33,7 @@ export default class PagesManifestPlugin appDirEnabled, }: { dev: boolean - distDir: string + distDir?: string isEdgeRuntime: boolean appDirEnabled: boolean }) { @@ -43,7 +43,7 @@ export default class PagesManifestPlugin this.appDirEnabled = appDirEnabled } - async createAssets(compilation: any) { + async createAssets(compilation: any, assets: any) { const entrypoints = compilation.entrypoints const pages: PagesManifest = {} const appPaths: PagesManifest = {} @@ -121,22 +121,57 @@ export default class PagesManifestPlugin ) } - const pagesManifestPath = path.join(this.distDir, 'server', PAGES_MANIFEST) - await writeMergedManifest(pagesManifestPath, { - ...edgeServerPages, - ...nodeServerPages, - }) - - if (this.appDirEnabled) { - const appPathsManifestPath = path.join( + if (this.distDir) { + const pagesManifestPath = path.join( this.distDir, 'server', - APP_PATHS_MANIFEST + PAGES_MANIFEST ) - await writeMergedManifest(appPathsManifestPath, { - ...edgeServerAppPaths, - ...nodeServerAppPaths, + await writeMergedManifest(pagesManifestPath, { + ...edgeServerPages, + ...nodeServerPages, }) + } else { + assets[ + `${!this.dev && !this.isEdgeRuntime ? '../' : ''}` + PAGES_MANIFEST + ] = new sources.RawSource( + JSON.stringify( + { + ...edgeServerPages, + ...nodeServerPages, + }, + null, + 2 + ) + ) + } + + if (this.appDirEnabled) { + if (this.distDir) { + const appPathsManifestPath = path.join( + this.distDir, + 'server', + APP_PATHS_MANIFEST + ) + await writeMergedManifest(appPathsManifestPath, { + ...edgeServerAppPaths, + ...nodeServerAppPaths, + }) + } else { + assets[ + `${!this.dev && !this.isEdgeRuntime ? '../' : ''}` + + APP_PATHS_MANIFEST + ] = new sources.RawSource( + JSON.stringify( + { + ...edgeServerAppPaths, + ...nodeServerAppPaths, + }, + null, + 2 + ) + ) + } } } @@ -147,7 +182,7 @@ export default class PagesManifestPlugin name: 'NextJsPagesManifest', stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS, }, - () => this.createAssets(compilation) + (assets) => this.createAssets(compilation, assets) ) }) }