diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 6887cd2865b1708..a29110bdc0966be 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -536,6 +536,7 @@ export default async function build( ) let mappedAppPages: { [page: string]: string } | undefined + let denormalizedAppPages: string[] | undefined if (appPaths && appDir) { mappedAppPages = nextBuildSpan @@ -586,7 +587,8 @@ export default async function build( const conflictingAppPagePaths: [pagePath: string, appPath: string][] = [] const appPageKeys: string[] = [] if (mappedAppPages) { - for (const appKey in mappedAppPages) { + denormalizedAppPages = Object.keys(mappedAppPages) + for (const appKey of denormalizedAppPages) { const normalizedAppPageKey = normalizeAppPath(appKey) || '/' const pagePath = mappedPages[normalizedAppPageKey] if (pagePath) { @@ -596,7 +598,6 @@ export default async function build( appPath.replace(/^private-next-app-dir/, 'app'), ]) } - appPageKeys.push(normalizedAppPageKey) } } @@ -2068,7 +2069,7 @@ export default async function build( dir, distDir, pageKeys.pages, - pageKeys.app, + denormalizedAppPages, outputFileTracingRoot, requiredServerFiles.config, middlewareManifest diff --git a/packages/next/build/utils.ts b/packages/next/build/utils.ts index eb9670a638c640f..614270f40c31195 100644 --- a/packages/next/build/utils.ts +++ b/packages/next/build/utils.ts @@ -1597,7 +1597,7 @@ export function detectConflictingPaths( export async function copyTracedFiles( dir: string, distDir: string, - pageKeys: ReadonlyArray, + pageKeys: readonly string[], appPageKeys: readonly string[] | undefined, tracingRoot: string, serverConfig: { [key: string]: any }, @@ -1712,7 +1712,7 @@ export async function copyTracedFiles( if (middlewareManifest.functions.hasOwnProperty(page)) { continue } - const pageFile = path.join(distDir, 'server', 'app', `${page}`, 'page.js') + const pageFile = path.join(distDir, 'server', 'app', `${page}.js`) const pageTraceFile = `${pageFile}.nft.json` await handleTraceFiles(pageTraceFile).catch((err) => { Log.warn(`Failed to copy traced files for ${pageFile}`, err) diff --git a/test/e2e/app-dir/standalone.test.ts b/test/e2e/app-dir/standalone.test.ts index 4ed2da4beafd250..8860e0b4a73f645 100644 --- a/test/e2e/app-dir/standalone.test.ts +++ b/test/e2e/app-dir/standalone.test.ts @@ -40,10 +40,39 @@ describe('output: standalone with app dir', () => { await next.destroy() }) + if ((global as any).isNextStart) { + it('should handle trace files correctly for route groups (nodejs only)', async () => { + expect(next.cliOutput).not.toContain('Failed to copy traced files') + const serverDirPath = path.join( + next.testDir, + '.next/standalone/.next/server' + ) + for (const page of [ + '(newroot)/dashboard/another', + '(newroot)/dashboard/project/[projectId]', + '(rootonly)/dashboard/changelog', + ]) { + const pagePath = path.join(serverDirPath, 'app', page) + + expect( + await fs.pathExists(path.join(pagePath, 'page.js.nft.json')) + ).toBe(true) + + const files = ( + await fs.readJSON(path.join(pagePath, 'page.js.nft.json')) + ).files as string[] + + for (const file of files) { + expect(await fs.pathExists(path.join(pagePath, file))).toBe(true) + } + } + }) + } + it('should work correctly with output standalone', async () => { const tmpFolder = path.join(os.tmpdir(), 'next-standalone-' + Date.now()) await fs.move(path.join(next.testDir, '.next/standalone'), tmpFolder) - let server + let server: any try { const testServer = path.join(tmpFolder, 'server.js') @@ -66,7 +95,12 @@ describe('output: standalone with app dir', () => { '/api/hello', '/blog/first', '/dashboard', + '/dashboard/another', + '/dashboard/changelog', + '/dashboard/deployments/breakdown', '/dashboard/deployments/123', + '/dashboard/hello', + '/dashboard/project/123', '/catch-all/first', ]) { const res = await fetchViaHTTP(appPort, testPath)