diff --git a/packages/next/build/analysis/get-page-static-info.ts b/packages/next/build/analysis/get-page-static-info.ts index 9b1ac0f48984..60d94aa800e3 100644 --- a/packages/next/build/analysis/get-page-static-info.ts +++ b/packages/next/build/analysis/get-page-static-info.ts @@ -1,4 +1,4 @@ -import type { ServerRuntime } from '../../server/config-shared' +import { isServerRuntime, ServerRuntime } from '../../server/config-shared' import type { NextConfig } from '../../server/config-shared' import { tryToExtractExportedConstValue } from './extract-const-value' import { escapeStringRegexp } from '../../shared/lib/escape-regexp' @@ -40,6 +40,24 @@ export async function getPageStaticInfo(params: { const { ssg, ssr } = checkExports(swcAST) const config = tryToExtractExportedConstValue(swcAST, 'config') || {} + if ( + typeof config.runtime !== 'string' && + typeof config.runtime !== 'undefined' + ) { + 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( + `The \`runtime\` config must be a string. Please leave it empty or choose one of: ${options}` + ) + } else { + throw new Error( + `Provided runtime "${config.runtime}" is not supported. Please leave it empty or choose one of: ${options}` + ) + } + } + let runtime = SERVER_RUNTIME.edge === config?.runtime ? SERVER_RUNTIME.edge diff --git a/packages/next/server/config-shared.ts b/packages/next/server/config-shared.ts index 0fa304656efa..6737be3cc1ec 100644 --- a/packages/next/server/config-shared.ts +++ b/packages/next/server/config-shared.ts @@ -561,3 +561,9 @@ export async function normalizeConfig(phase: string, config: any) { // Support `new Promise` and `async () =>` as return values of the config export return await config } + +export function isServerRuntime(value?: string): value is ServerRuntime { + return ( + value === undefined || value === 'nodejs' || value === 'experimental-edge' + ) +} diff --git a/test/production/exported-runtimes-value-validation/app/pages/index.js b/test/production/exported-runtimes-value-validation/app/pages/index.js new file mode 100644 index 000000000000..33c8e487c86d --- /dev/null +++ b/test/production/exported-runtimes-value-validation/app/pages/index.js @@ -0,0 +1,7 @@ +export default function Page() { + return

hello world

+} + +export const config = { + runtime: 'something-odd', +} diff --git a/test/production/exported-runtimes-value-validation/index.test.ts b/test/production/exported-runtimes-value-validation/index.test.ts new file mode 100644 index 000000000000..73d4009ff442 --- /dev/null +++ b/test/production/exported-runtimes-value-validation/index.test.ts @@ -0,0 +1,18 @@ +import { nextBuild } from 'next-test-utils' +import path from 'path' + +describe('Exported runtimes value validation', () => { + test('fails to build on malformed input', async () => { + const result = await nextBuild( + path.resolve(__dirname, './app'), + undefined, + { stdout: true, stderr: true } + ) + expect(result).toMatchObject({ + code: 1, + stderr: expect.stringContaining( + `Provided runtime "something-odd" is not supported.` + ), + }) + }) +})