From 01168eff73a1eee1dcd25a6f47ab0673afaa9772 Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Fri, 14 Jun 2024 11:50:57 +0200 Subject: [PATCH] do Next.js version verification earlier and make it easy to grab the version after build command finished --- src/build/content/server.ts | 20 +++----------------- src/build/plugin-context.ts | 21 +++++++++++++++++++++ src/build/verification.ts | 17 +++++++++-------- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/build/content/server.ts b/src/build/content/server.ts index dc38fce665..dcf497cf4e 100644 --- a/src/build/content/server.ts +++ b/src/build/content/server.ts @@ -20,7 +20,6 @@ import { prerelease, lt as semverLowerThan, lte as semverLowerThanOrEqual } from import { RUN_CONFIG } from '../../run/constants.js' import { PluginContext } from '../plugin-context.js' -import { verifyNextVersion } from '../verification.js' const tracer = wrapTracer(trace.getTracer('Next runtime')) @@ -292,26 +291,13 @@ export const copyNextDependencies = async (ctx: PluginContext): Promise => await Promise.all(promises) - // detect if it might lead to a runtime issue and throw an error upfront on build time instead of silently failing during runtime const serverHandlerRequire = createRequire(posixJoin(ctx.serverHandlerDir, ':internal:')) - let nextVersion: string | undefined - try { - const { version } = serverHandlerRequire('next/package.json') - if (version) { - nextVersion = version as string - } - } catch { - // failed to resolve package.json - currently this is resolvable in all known next versions, but if next implements - // exports map it still might be a problem in the future, so we are not breaking here - } - - if (nextVersion) { - verifyNextVersion(ctx, nextVersion) - - await patchNextModules(ctx, nextVersion, serverHandlerRequire.resolve) + if (ctx.nextVersion) { + await patchNextModules(ctx, ctx.nextVersion, serverHandlerRequire.resolve) } + // detect if it might lead to a runtime issue and throw an error upfront on build time instead of silently failing during runtime try { const nextEntryAbsolutePath = serverHandlerRequire.resolve('next') const nextRequire = createRequire(nextEntryAbsolutePath) diff --git a/src/build/plugin-context.ts b/src/build/plugin-context.ts index feedfcfeed..a28148db96 100644 --- a/src/build/plugin-context.ts +++ b/src/build/plugin-context.ts @@ -1,6 +1,8 @@ import { existsSync, readFileSync } from 'node:fs' import { readFile } from 'node:fs/promises' +import { createRequire } from 'node:module' import { join, relative, resolve } from 'node:path' +import { join as posixJoin } from 'node:path/posix' import { fileURLToPath } from 'node:url' import type { @@ -313,6 +315,25 @@ export class PluginContext { return JSON.parse(await readFile(join(this.publishDir, 'routes-manifest.json'), 'utf-8')) } + #nextVersion: string | null | undefined = undefined + + /** + * Get Next.js version that was used to build the site + */ + get nextVersion(): string | null { + if (this.#nextVersion === undefined) { + try { + const serverHandlerRequire = createRequire(posixJoin(this.standaloneRootDir, ':internal:')) + const { version } = serverHandlerRequire('next/package.json') + this.#nextVersion = version as string + } catch { + this.#nextVersion = null + } + } + + return this.#nextVersion + } + /** Fails a build with a message and an optional error */ failBuild(message: string, error?: unknown): never { return this.utils.build.failBuild(message, error instanceof Error ? { error } : undefined) diff --git a/src/build/verification.ts b/src/build/verification.ts index 269838daf3..6589cb67c1 100644 --- a/src/build/verification.ts +++ b/src/build/verification.ts @@ -47,6 +47,15 @@ export function verifyPublishDir(ctx: PluginContext) { `Your publish directory does not contain expected Next.js build output. Please make sure you are using Next.js version (${SUPPORTED_NEXT_VERSIONS})`, ) } + + if ( + ctx.nextVersion && + !satisfies(ctx.nextVersion, SUPPORTED_NEXT_VERSIONS, { includePrerelease: true }) + ) { + ctx.failBuild( + `@netlify/plugin-next@5 requires Next.js version ${SUPPORTED_NEXT_VERSIONS}, but found ${ctx.nextVersion}. Please upgrade your project's Next.js version.`, + ) + } } if (ctx.buildConfig.output === 'export') { if (!ctx.exportDetail?.success) { @@ -60,14 +69,6 @@ export function verifyPublishDir(ctx: PluginContext) { } } -export function verifyNextVersion(ctx: PluginContext, nextVersion: string): void | never { - if (!satisfies(nextVersion, SUPPORTED_NEXT_VERSIONS, { includePrerelease: true })) { - ctx.failBuild( - `@netlify/plugin-next@5 requires Next.js version ${SUPPORTED_NEXT_VERSIONS}, but found ${nextVersion}. Please upgrade your project's Next.js version.`, - ) - } -} - export async function verifyNoAdvancedAPIRoutes(ctx: PluginContext) { const apiRoutesConfigs = await getAPIRoutesConfigs(ctx)