diff --git a/.changeset/hot-forks-try.md b/.changeset/hot-forks-try.md new file mode 100644 index 000000000..9d6a44364 --- /dev/null +++ b/.changeset/hot-forks-try.md @@ -0,0 +1,5 @@ +--- +'@cloudflare/next-on-pages': minor +--- + +Add `force` CLI option to ignore invalid functions diff --git a/packages/next-on-pages/src/buildApplication/buildApplication.ts b/packages/next-on-pages/src/buildApplication/buildApplication.ts index 92741382b..ed55a55ea 100644 --- a/packages/next-on-pages/src/buildApplication/buildApplication.ts +++ b/packages/next-on-pages/src/buildApplication/buildApplication.ts @@ -30,6 +30,7 @@ export async function buildApplication({ watch, outdir: outputDir, customEntrypoint, + force, }: Pick< CliOptions, | 'skipBuild' @@ -38,6 +39,7 @@ export async function buildApplication({ | 'watch' | 'outdir' | 'customEntrypoint' + | 'force' >) { const pm = await getPackageManager(); @@ -87,6 +89,7 @@ export async function buildApplication({ disableChunksDedup, disableWorkerMinification, customEntrypoint, + force, }); const totalBuildTime = ((Date.now() - buildStartTime) / 1000).toFixed(2); @@ -99,9 +102,13 @@ async function prepareAndBuildWorker( disableChunksDedup, disableWorkerMinification, customEntrypoint, + force, }: Pick< CliOptions, - 'disableChunksDedup' | 'disableWorkerMinification' | 'customEntrypoint' + | 'disableChunksDedup' + | 'disableWorkerMinification' + | 'customEntrypoint' + | 'force' >, ): Promise { let vercelConfig: VercelConfig; @@ -137,6 +144,7 @@ async function prepareAndBuildWorker( nopDistDir, disableChunksDedup, vercelConfig, + ignoreInvalidFunctions: force, }); } diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/index.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/index.ts index d980a75e2..55507821b 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/index.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/index.ts @@ -37,6 +37,7 @@ export type ProcessVercelFunctionsOpts = { nopDistDir: string; disableChunksDedup?: boolean; vercelConfig: VercelConfig; + ignoreInvalidFunctions: boolean; }; export type ProcessedVercelFunctions = { diff --git a/packages/next-on-pages/src/buildApplication/processVercelFunctions/invalidFunctions.ts b/packages/next-on-pages/src/buildApplication/processVercelFunctions/invalidFunctions.ts index d6d92d729..f84fb2430 100644 --- a/packages/next-on-pages/src/buildApplication/processVercelFunctions/invalidFunctions.ts +++ b/packages/next-on-pages/src/buildApplication/processVercelFunctions/invalidFunctions.ts @@ -14,7 +14,7 @@ import { isUsingAppRouter, isUsingPagesRouter } from '../getVercelConfig'; type InvalidFunctionsOpts = Pick< ProcessVercelFunctionsOpts, 'functionsDir' | 'vercelConfig' ->; +> & { ignoreInvalidFunctions?: boolean }; /** * Checks if there are any invalid functions from the Vercel build output. @@ -46,7 +46,10 @@ export async function checkInvalidFunctions( await tryToFixInvalidFuncsWithValidIndexAlternative(collectedFunctions); await tryToFixInvalidDynamicISRFuncs(collectedFunctions); - if (collectedFunctions.invalidFunctions.size > 0) { + if ( + collectedFunctions.invalidFunctions.size > 0 && + !opts.ignoreInvalidFunctions + ) { await printInvalidFunctionsErrorMessage( collectedFunctions.invalidFunctions, ); diff --git a/packages/next-on-pages/src/cli.ts b/packages/next-on-pages/src/cli.ts index 277d2ce94..efadd480a 100644 --- a/packages/next-on-pages/src/cli.ts +++ b/packages/next-on-pages/src/cli.ts @@ -62,6 +62,7 @@ program '--custom-entrypoint ', 'Wrap the generated worker for your application in a custom worker entrypoint', ) + .option('-f, --force', 'Ignore checks for edge runtime compatibility', false) .enablePositionalOptions(false) .version( nextOnPagesVersion, @@ -79,6 +80,7 @@ export type CliOptions = { info?: boolean; outdir: string; customEntrypoint?: string; + force: boolean; }; export function parseCliArgs(): CliOptions { diff --git a/packages/next-on-pages/tests/_helpers/index.ts b/packages/next-on-pages/tests/_helpers/index.ts index ed9b99cf2..14db914af 100644 --- a/packages/next-on-pages/tests/_helpers/index.ts +++ b/packages/next-on-pages/tests/_helpers/index.ts @@ -223,6 +223,7 @@ export async function createRouterTestData( nopDistDir: join(workerJsDir, '__next-on-pages-dist__'), disableChunksDedup: true, vercelConfig: { version: 3 }, + ignoreInvalidFunctions: false, }); const staticAssets = await getVercelStaticAssets(); diff --git a/packages/next-on-pages/tests/src/buildApplication/processVercelFunctions/invalidFunctions.test.ts b/packages/next-on-pages/tests/src/buildApplication/processVercelFunctions/invalidFunctions.test.ts index 8cb1bb226..013202d2c 100644 --- a/packages/next-on-pages/tests/src/buildApplication/processVercelFunctions/invalidFunctions.test.ts +++ b/packages/next-on-pages/tests/src/buildApplication/processVercelFunctions/invalidFunctions.test.ts @@ -341,4 +341,54 @@ describe('checkInvalidFunctions', () => { mockedConsoleError.restore(); mockedConsoleWarn.restore(); }); + + test('should ignore invalid functions when opted in', async () => { + const processExitMock = vi + .spyOn(process, 'exit') + .mockImplementation(async () => undefined as never); + + const { collectedFunctions, restoreFsMock } = await collectFunctionsFrom({ + functions: { + '[dynamic-1].func': prerenderFuncDir, + 'edge-route.func': edgeFuncDir, + }, + }); + + const opts = { + functionsDir, + outputDir: resolve('.vercel/output/static'), + vercelConfig: { version: 3 as const }, + ignoreInvalidFunctions: true, + }; + + await processEdgeFunctions(collectedFunctions); + await processPrerenderFunctions(collectedFunctions, opts); + await checkInvalidFunctions(collectedFunctions, opts); + restoreFsMock(); + + const { + edgeFunctions, + prerenderedFunctions, + invalidFunctions, + ignoredFunctions, + } = collectedFunctions; + + expect(edgeFunctions.size).toEqual(1); + expect(prerenderedFunctions.size).toEqual(0); + expect(invalidFunctions.size).toEqual(1); + expect(ignoredFunctions.size).toEqual(0); + + expect(getRouteInfo(edgeFunctions, 'edge-route.func')).toEqual({ + path: '/edge-route', + overrides: [], + }); + + expect([...invalidFunctions.keys()]).toEqual([ + resolve(functionsDir, '[dynamic-1].func'), + ]); + + expect(processExitMock).not.toBeCalled(); + + processExitMock.mockRestore(); + }); });