From 16cf88e569552fe5060f1d28a657b749b967528d Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Sun, 23 Jun 2024 12:21:10 +0200 Subject: [PATCH] Add experimental flag for providing entry paths (#67134) Adds a flag for experimentally building on specifically provided entry paths. This should not be relied on as it is NOT a public facing API. --- packages/next/src/build/index.ts | 53 ++++++++++++++-------- packages/next/src/server/config-shared.ts | 2 +- test/e2e/app-dir/app/provide-paths.test.ts | 53 ++++++++++++++++++++++ test/turbopack-build-tests-manifest.json | 5 ++ 4 files changed, 92 insertions(+), 21 deletions(-) create mode 100644 test/e2e/app-dir/app/provide-paths.test.ts diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index 6ec64345cce6f..be8d48c59b3b0 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -866,14 +866,20 @@ export default async function build( appDir ) - const pagesPaths = - !appDirOnly && pagesDir - ? await nextBuildSpan.traceChild('collect-pages').traceAsyncFn(() => - recursiveReadDir(pagesDir, { - pathnameFilter: validFileMatcher.isPageFile, - }) - ) - : [] + const providedPagePaths: string[] = JSON.parse( + process.env.NEXT_PROVIDED_PAGE_PATHS || '[]' + ) + + let pagesPaths = + providedPagePaths.length > 0 + ? providedPagePaths + : !appDirOnly && pagesDir + ? await nextBuildSpan.traceChild('collect-pages').traceAsyncFn(() => + recursiveReadDir(pagesDir, { + pathnameFilter: validFileMatcher.isPageFile, + }) + ) + : [] const middlewareDetectionRegExp = new RegExp( `^${MIDDLEWARE_FILENAME}\\.(?:${config.pageExtensions.join('|')})$` @@ -936,18 +942,25 @@ export default async function build( let denormalizedAppPages: string[] | undefined if (appDir) { - const appPaths = await nextBuildSpan - .traceChild('collect-app-paths') - .traceAsyncFn(() => - recursiveReadDir(appDir, { - pathnameFilter: (absolutePath) => - validFileMatcher.isAppRouterPage(absolutePath) || - // For now we only collect the root /not-found page in the app - // directory as the 404 fallback - validFileMatcher.isRootNotFound(absolutePath), - ignorePartFilter: (part) => part.startsWith('_'), - }) - ) + const providedAppPaths: string[] = JSON.parse( + process.env.NEXT_PROVIDED_APP_PATHS || '[]' + ) + + let appPaths = + providedAppPaths.length > 0 + ? providedAppPaths + : await nextBuildSpan + .traceChild('collect-app-paths') + .traceAsyncFn(() => + recursiveReadDir(appDir, { + pathnameFilter: (absolutePath) => + validFileMatcher.isAppRouterPage(absolutePath) || + // For now we only collect the root /not-found page in the app + // directory as the 404 fallback + validFileMatcher.isRootNotFound(absolutePath), + ignorePartFilter: (part) => part.startsWith('_'), + }) + ) mappedAppPages = await nextBuildSpan .traceChild('create-app-mapping') diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index da6248b3c5c0a..bdfebcebf5e68 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -921,7 +921,7 @@ export const defaultConfig: NextConfig = { output: !!process.env.NEXT_PRIVATE_STANDALONE ? 'standalone' : undefined, modularizeImports: undefined, experimental: { - flyingShuttle: false, + flyingShuttle: Boolean(process.env.NEXT_PRIVATE_FLYING_SHUTTLE), prerenderEarlyExit: true, serverMinification: true, serverSourceMaps: false, diff --git a/test/e2e/app-dir/app/provide-paths.test.ts b/test/e2e/app-dir/app/provide-paths.test.ts new file mode 100644 index 0000000000000..189b2414d1955 --- /dev/null +++ b/test/e2e/app-dir/app/provide-paths.test.ts @@ -0,0 +1,53 @@ +import { nextTestSetup } from 'e2e-utils' +import glob from 'glob' +import path from 'path' + +describe('Provided page/app paths', () => { + const { next, isNextDev } = nextTestSetup({ + files: __dirname, + dependencies: { + nanoid: '4.0.1', + }, + env: { + NEXT_PROVIDED_PAGE_PATHS: JSON.stringify(['/index.js', '/ssg.js']), + NEXT_PROVIDED_APP_PATHS: JSON.stringify([ + '/dashboard/page.js', + '/(newroot)/dashboard/another/page.js', + ]), + }, + }) + + if (isNextDev) { + it('should skip dev', () => {}) + return + } + + it('should only build the provided paths', async () => { + const appPaths = await glob.sync('**/*.js', { + cwd: path.join(next.testDir, '.next/server/app'), + }) + const pagePaths = await glob.sync('**/*.js', { + cwd: path.join(next.testDir, '.next/server/pages'), + }) + + expect(appPaths).toEqual([ + '_not-found/page_client-reference-manifest.js', + '_not-found/page.js', + '(newroot)/dashboard/another/page_client-reference-manifest.js', + '(newroot)/dashboard/another/page.js', + 'dashboard/page_client-reference-manifest.js', + 'dashboard/page.js', + ]) + expect(pagePaths).toEqual([ + '_app.js', + '_document.js', + '_error.js', + 'ssg.js', + ]) + + for (const pathname of ['/', '/ssg', '/dashboard', '/dashboard/another']) { + const res = await next.fetch(pathname) + expect(res.status).toBe(200) + } + }) +}) diff --git a/test/turbopack-build-tests-manifest.json b/test/turbopack-build-tests-manifest.json index a872c743dbd46..d66feae98a92a 100644 --- a/test/turbopack-build-tests-manifest.json +++ b/test/turbopack-build-tests-manifest.json @@ -1,6 +1,11 @@ { "version": 2, "suites": { + "test/e2e/app-dir/app/provide-paths.test.ts": { + "passed": [], + "pending": [], + "failed": ["Provided page/app paths should only build the provided paths"] + }, "test/e2e/404-page-router/index.test.ts": { "passed": [ "404-page-router 404-page-router with basePath of false and i18n of false and middleware false for /error should have the correct router parameters after it is ready",