diff --git a/packages/next/build/webpack/plugins/next-trace-entrypoints-plugin.ts b/packages/next/build/webpack/plugins/next-trace-entrypoints-plugin.ts index c34360b065600..e228934e9ea3d 100644 --- a/packages/next/build/webpack/plugins/next-trace-entrypoints-plugin.ts +++ b/packages/next/build/webpack/plugins/next-trace-entrypoints-plugin.ts @@ -76,13 +76,12 @@ export class TraceEntryPointsPlugin implements webpack.Plugin { assets[traceOutputName] = new sources.RawSource( JSON.stringify({ version: TRACE_OUTPUT_VERSION, - files: [...entryFiles, ...this.entryTraces.get(entrypoint.name)!].map( - (file) => { - return nodePath - .relative(traceOutputPath, file) - .replace(/\\/g, '/') - } - ), + files: [ + ...entryFiles, + ...(this.entryTraces.get(entrypoint.name) || []), + ].map((file) => { + return nodePath.relative(traceOutputPath, file).replace(/\\/g, '/') + }), }) ) } @@ -118,6 +117,7 @@ export class TraceEntryPointsPlugin implements webpack.Plugin { // over the compilation modules list const entryNameMap = new Map() const entryModMap = new Map() + const additionalEntries = new Map>() try { const depModMap = new Map() @@ -125,15 +125,27 @@ export class TraceEntryPointsPlugin implements webpack.Plugin { compilation.entries.forEach((entry) => { const name = entry.name || entry.options?.name - if (name?.startsWith('pages/') && entry.dependencies[0]) { - const entryMod = getModuleFromDependency( - compilation, - entry.dependencies[0] - ) + if (name?.replace(/\\/g, '/').startsWith('pages/')) { + for (const dep of entry.dependencies) { + if (!dep) continue + const entryMod = getModuleFromDependency(compilation, dep) + + if (entryMod && entryMod.resource) { + if ( + entryMod.resource.replace(/\\/g, '/').includes('pages/') + ) { + entryNameMap.set(entryMod.resource, name) + entryModMap.set(entryMod.resource, entryMod) + } else { + let curMap = additionalEntries.get(name) - if (entryMod.resource) { - entryNameMap.set(entryMod.resource, name) - entryModMap.set(entryMod.resource, entryMod) + if (!curMap) { + curMap = new Map() + additionalEntries.set(name, curMap) + } + curMap.set(entryMod.resource, entryMod) + } + } } } }) @@ -225,6 +237,13 @@ export class TraceEntryPointsPlugin implements webpack.Plugin { const toTrace: string[] = [entry, ...depModMap.keys()] + const entryName = entryNameMap.get(entry)! + const curExtraEntries = additionalEntries.get(entryName) + + if (curExtraEntries) { + toTrace.push(...curExtraEntries.keys()) + } + const root = nodePath.parse(process.cwd()).root const result = await nodeFileTrace(toTrace, { base: root, @@ -249,7 +268,7 @@ export class TraceEntryPointsPlugin implements webpack.Plugin { // version: TRACE_OUTPUT_VERSION, // tracedDeps, // } - this.entryTraces.set(entryNameMap.get(entry)!, tracedDeps) + this.entryTraces.set(entryName, tracedDeps) } callback() diff --git a/test/integration/build-trace-extra-entries/content/hello.json b/test/integration/build-trace-extra-entries/content/hello.json new file mode 100644 index 0000000000000..f2a886f39de7d --- /dev/null +++ b/test/integration/build-trace-extra-entries/content/hello.json @@ -0,0 +1,3 @@ +{ + "hello": "world" +} diff --git a/test/integration/build-trace-extra-entries/lib/get-data.js b/test/integration/build-trace-extra-entries/lib/get-data.js new file mode 100644 index 0000000000000..1ae25f9d78599 --- /dev/null +++ b/test/integration/build-trace-extra-entries/lib/get-data.js @@ -0,0 +1,8 @@ +import fs from 'fs' +import path from 'path' + +export function getData() { + return JSON.parse( + fs.readFileSync(path.join(process.cwd(), 'content/hello.json'), 'utf8') + ) +} diff --git a/test/integration/build-trace-extra-entries/next.config.js b/test/integration/build-trace-extra-entries/next.config.js new file mode 100644 index 0000000000000..9cac96cfac31d --- /dev/null +++ b/test/integration/build-trace-extra-entries/next.config.js @@ -0,0 +1,25 @@ +const path = require('path') + +module.exports = { + experimental: { + nftTracing: true, + }, + webpack(cfg, { isServer }) { + console.log(cfg.entry) + const origEntry = cfg.entry + cfg.entry = async () => { + const origEntries = await origEntry() + + if (isServer) { + const curEntry = origEntries['pages/_app'] + origEntries['pages/_app'] = [ + path.resolve('lib/get-data.js'), + ...curEntry, + ] + console.log(origEntries) + } + return origEntries + } + return cfg + }, +} diff --git a/test/integration/build-trace-extra-entries/pages/index.js b/test/integration/build-trace-extra-entries/pages/index.js new file mode 100644 index 0000000000000..76c8a590e002c --- /dev/null +++ b/test/integration/build-trace-extra-entries/pages/index.js @@ -0,0 +1,3 @@ +export default function Page() { + return 'index page' +} diff --git a/test/integration/build-trace-extra-entries/test/index.test.js b/test/integration/build-trace-extra-entries/test/index.test.js new file mode 100644 index 0000000000000..e53dbbc0caea2 --- /dev/null +++ b/test/integration/build-trace-extra-entries/test/index.test.js @@ -0,0 +1,32 @@ +/* eslint-env jest */ + +import fs from 'fs-extra' +import { join } from 'path' +import { nextBuild } from 'next-test-utils' + +jest.setTimeout(1000 * 60) + +const appDir = join(__dirname, '..') + +describe('build trace with extra entries', () => { + it('should build and trace correctly', async () => { + const result = await nextBuild(appDir, undefined, { + cwd: appDir, + }) + expect(result.code).toBe(0) + + const appTrace = await fs.readJSON( + join(appDir, '.next/server/pages/_app.js.nft.json') + ) + const indexTrace = await fs.readJSON( + join(appDir, '.next/server/pages/index.js.nft.json') + ) + + expect(appTrace.files.some((file) => file.endsWith('hello.json'))).toBe( + true + ) + expect( + indexTrace.files.some((file) => file.endsWith('hello.json')) + ).toBeFalsy() + }) +})