diff --git a/src/kit/index.ts b/src/kit/index.ts index 9a91fff321..607b237ed4 100644 --- a/src/kit/index.ts +++ b/src/kit/index.ts @@ -1,4 +1,4 @@ -export { defineNitroPreset } from "./preset"; +export { defineNitroPreset, getDefaultNodeVersion } from "./preset"; export { defineNitroModule } from "./module"; export { writeFile, isDirectory } from "./fs"; diff --git a/src/kit/preset.ts b/src/kit/preset.ts index 8a10b39740..b5603783ed 100644 --- a/src/kit/preset.ts +++ b/src/kit/preset.ts @@ -15,3 +15,41 @@ export function defineNitroPreset< } return { ...preset, _meta: meta } as P & { _meta: M }; } + +const DEFAULT_NODE_VERSION = 20 as const; + +/** + * Builder to get the default Node.js version for a provider. + * + * Ideally, all presets will support Nitro's preferred `DEFAULT_NODE_VERSION`, + * which will simply be converted to a preset-specific identifier. + * If not, it will return the highest supported version below `DEFAULT_NODE_VERSION`. + * + * @param supportedNodeVersions - A set of Node.js version numbers supported by the provider. + * @param getNodeVerisonString - A preset-specific function to convert a Node.js version number to the runtime string. Defaults to String constructor. + * @returns The Node.js version identifier for preset. + */ +export function getDefaultNodeVersion( + supportedNodeVersions: Set, + getNodeVerisonString: (version: number) => string = String +): string { + // Get Nitro's current default Node.js version + let version = DEFAULT_NODE_VERSION; + + // Check it is supported by the provider + if (supportedNodeVersions.has(version)) { + // If so, return the mapped version + return getNodeVerisonString(version); + } + + // Else, return the latest supported version + while (version > 10) { + version--; + if (supportedNodeVersions.has(version)) { + // Found the next-highest supported version + return getNodeVerisonString(version); + } + } + + throw new Error("No supported Node.js version found"); +} diff --git a/src/presets/azure/utils.ts b/src/presets/azure/utils.ts index b6fba139bb..24e3cb65f7 100644 --- a/src/presets/azure/utils.ts +++ b/src/presets/azure/utils.ts @@ -1,9 +1,9 @@ import { createWriteStream } from "node:fs"; -import fsp from "node:fs/promises"; import archiver from "archiver"; -import { writeFile } from "nitropack/kit"; +import { getDefaultNodeVersion, writeFile } from "nitropack/kit"; import type { Nitro } from "nitropack/types"; import { join, resolve } from "pathe"; +import { readPackageJSON } from "pkg-types"; export async function writeFunctionsRoutes(nitro: Nitro) { const host = { @@ -49,22 +49,18 @@ export async function writeSWARoutes(nitro: Nitro) { version: "2.0", }; - // https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=typescript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4#supported-versions - const supportedNodeVersions = new Set(["16", "18", "20"]); - let nodeVersion = "18"; - try { - const currentNodeVersion = JSON.parse( - await fsp.readFile(join(nitro.options.rootDir, "package.json"), "utf8") - ).engines.node; - if (supportedNodeVersions.has(currentNodeVersion)) { - nodeVersion = currentNodeVersion; - } - } catch { - const currentNodeVersion = process.versions.node.slice(0, 2); - if (supportedNodeVersions.has(currentNodeVersion)) { - nodeVersion = currentNodeVersion; - } - } + /** @link https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=typescript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4#supported-versions */ + const supportedNodeVersions = new Set([16, 18, 20]); + + // Read package.json to get the current node version + const packageJSONPath = join(nitro.options.rootDir, "package.json"); + const packageJSON = await readPackageJSON(packageJSONPath); + const currentNodeVersion = Number.parseInt(packageJSON.engines?.node); + /* If current node version is supported, use it, + otherwise use the default node version */ + const nodeVersion = supportedNodeVersions.has(currentNodeVersion) + ? currentNodeVersion + : getDefaultNodeVersion(supportedNodeVersions); // Merge custom config into the generated config const config = { diff --git a/src/presets/firebase/utils.ts b/src/presets/firebase/utils.ts index 9e1501051e..8b291bfe8e 100644 --- a/src/presets/firebase/utils.ts +++ b/src/presets/firebase/utils.ts @@ -1,10 +1,16 @@ import { existsSync } from "node:fs"; -import { writeFile } from "nitropack/kit"; +import { writeFile, getDefaultNodeVersion } from "nitropack/kit"; import type { Nitro } from "nitropack/types"; import { join, relative } from "pathe"; import { readPackageJSON, writePackageJSON } from "pkg-types"; import type { FirebaseFunctionsOptions } from "./types"; +/** + * Supported Node.js versions for Firebase Functions. + * @link https://cloud.google.com/functions/docs/runtime-support#node.js + */ +const supportedNodeVersions = new Set([18, 20]); + export async function writeFirebaseConfig(nitro: Nitro) { const firebaseConfigPath = join(nitro.options.rootDir, "firebase.json"); if (existsSync(firebaseConfigPath)) { @@ -51,7 +57,7 @@ export async function updatePackageJSON(nitro: Nitro) { // https://cloud.google.com/functions/docs/concepts/nodejs-runtime node: (nitro.options.firebase as FirebaseFunctionsOptions)?.nodeVersion || - "20", + getDefaultNodeVersion(supportedNodeVersions), }, }); }