From 35253e1a938eb773310a7a28d8ab3f3be8462b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Wed, 7 Sep 2022 22:12:13 +0200 Subject: [PATCH] fix(switchable-runtime): make dev server not break when wrong runtime config is exported (#40312) Currently the DEV server can't recover if you export an invalid runtime config. It ends up in a state where it stops to work but nothing is printed to the terminal. It now prints an error but keeps working. When building it should crash, there's an existing test for that https://github.com/vercel/next.js/blob/canary/test/production/exported-runtimes-value-validation/index.test.ts#L5-L17 #### Reproduce ```tsx export default function Page() { return

hello world

} export const config = { runtime: 'something-odd', } ``` --- .../build/analysis/get-page-static-info.ts | 13 ++-- packages/next/server/dev/hot-reloader.ts | 1 + packages/next/server/dev/next-dev-server.ts | 1 + .../server/dev/on-demand-entry-handler.ts | 1 + test/e2e/switchable-runtime/index.test.ts | 68 +++++++++++++++++++ .../pages/invalid-runtime.js | 3 + 6 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 test/e2e/switchable-runtime/pages/invalid-runtime.js diff --git a/packages/next/build/analysis/get-page-static-info.ts b/packages/next/build/analysis/get-page-static-info.ts index bcaaac6bd2cc..37d95e9bdcdd 100644 --- a/packages/next/build/analysis/get-page-static-info.ts +++ b/packages/next/build/analysis/get-page-static-info.ts @@ -239,21 +239,22 @@ export async function getPageStaticInfo(params: { } if ( - typeof config.runtime !== 'string' && - typeof config.runtime !== 'undefined' + typeof config.runtime !== 'undefined' && + !isServerRuntime(config.runtime) ) { - throw new Error(`Provided runtime `) - } else if (!isServerRuntime(config.runtime)) { const options = Object.values(SERVER_RUNTIME).join(', ') if (typeof config.runtime !== 'string') { - throw new Error( + Log.error( `The \`runtime\` config must be a string. Please leave it empty or choose one of: ${options}` ) } else { - throw new Error( + Log.error( `Provided runtime "${config.runtime}" is not supported. Please leave it empty or choose one of: ${options}` ) } + if (!isDev) { + process.exit(1) + } } let runtime = diff --git a/packages/next/server/dev/hot-reloader.ts b/packages/next/server/dev/hot-reloader.ts index 8e1d195b7c7b..7a7584b43bdc 100644 --- a/packages/next/server/dev/hot-reloader.ts +++ b/packages/next/server/dev/hot-reloader.ts @@ -602,6 +602,7 @@ export default class HotReloader { ? await getPageStaticInfo({ pageFilePath: entryData.absolutePagePath, nextConfig: this.config, + isDev: true, }) : {} diff --git a/packages/next/server/dev/next-dev-server.ts b/packages/next/server/dev/next-dev-server.ts index 920a6264845d..d360778905f4 100644 --- a/packages/next/server/dev/next-dev-server.ts +++ b/packages/next/server/dev/next-dev-server.ts @@ -369,6 +369,7 @@ export default class DevServer extends Server { pageFilePath: fileName, nextConfig: this.nextConfig, page: rootFile, + isDev: true, }) if (isMiddlewareFile(rootFile)) { diff --git a/packages/next/server/dev/on-demand-entry-handler.ts b/packages/next/server/dev/on-demand-entry-handler.ts index a0a2fe8bf171..1c752b7b296d 100644 --- a/packages/next/server/dev/on-demand-entry-handler.ts +++ b/packages/next/server/dev/on-demand-entry-handler.ts @@ -632,6 +632,7 @@ export function onDemandEntryHandler({ const staticInfo = await getPageStaticInfo({ pageFilePath: pagePathData.absolutePagePath, nextConfig, + isDev: true, }) const added = new Map>() diff --git a/test/e2e/switchable-runtime/index.test.ts b/test/e2e/switchable-runtime/index.test.ts index f21f94dba24b..b9cef7819887 100644 --- a/test/e2e/switchable-runtime/index.test.ts +++ b/test/e2e/switchable-runtime/index.test.ts @@ -202,6 +202,74 @@ describe('Switchable runtime', () => { }) } }) + + it('should not crash the dev server when invalid runtime is configured', async () => { + await check( + () => renderViaHTTP(next.url, '/invalid-runtime'), + /Hello from page without errors/ + ) + + // Invalid runtime type + await next.patchFile( + 'pages/invalid-runtime.js', + ` + export default function Page() { + return

Hello from page with invalid type

+ } + + export const config = { + runtime: 10, + } + ` + ) + await check( + () => renderViaHTTP(next.url, '/invalid-runtime'), + /Hello from page with invalid type/ + ) + expect(next.cliOutput).toInclude( + 'error - The `runtime` config must be a string. Please leave it empty or choose one of:' + ) + + // Invalid runtime + await next.patchFile( + 'pages/invalid-runtime.js', + ` + export default function Page() { + return

Hello from page with invalid runtime

+ } + + export const config = { + runtime: "asd" + } + ` + ) + await check( + () => renderViaHTTP(next.url, '/invalid-runtime'), + /Hello from page with invalid runtime/ + ) + expect(next.cliOutput).toInclude( + 'error - Provided runtime "asd" is not supported. Please leave it empty or choose one of:' + ) + + // Fix the runtime + await next.patchFile( + 'pages/invalid-runtime.js', + ` + export default function Page() { + return

Hello from page without errors

+ } + + export const config = { + runtime: 'experimental-edge', + } + + ` + ) + await check( + () => renderViaHTTP(next.url, '/invalid-runtime'), + /Hello from page without errors/ + ) + }) }) } else { describe('Switchable runtime (prod)', () => { diff --git a/test/e2e/switchable-runtime/pages/invalid-runtime.js b/test/e2e/switchable-runtime/pages/invalid-runtime.js new file mode 100644 index 000000000000..17235157127b --- /dev/null +++ b/test/e2e/switchable-runtime/pages/invalid-runtime.js @@ -0,0 +1,3 @@ +export default function Page() { + return

Hello from page without errors

+}