From 3e7ea0ae86f33ca0ebce2dc8387e3adbdd777423 Mon Sep 17 00:00:00 2001 From: Rihan Arfan Date: Thu, 24 Sep 2026 14:57:54 +0100 Subject: [PATCH 1/3] fix(cloudflare): guard nodejs_compat flag by compatibility date --- src/presets/cloudflare/utils.ts | 15 ++++++- test/unit/cloudflare.utils.test.ts | 67 ++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 test/unit/cloudflare.utils.test.ts diff --git a/src/presets/cloudflare/utils.ts b/src/presets/cloudflare/utils.ts index 46792ccbb4..31d263a026 100644 --- a/src/presets/cloudflare/utils.ts +++ b/src/presets/cloudflare/utils.ts @@ -23,6 +23,10 @@ import { unenvWorkerdWithNodeCompat, } from "../_unenv/preset-workerd"; +// https://github.com/nitrojs/nitro/issues/4527 +const NODEJS_COMPAT_SUPPORTED_FROM_DATE = "2024-09-23"; +const NODEJS_COMPAT_DEFAULT_ON_DATE = "2026-08-04"; + export async function writeCFRoutes(nitro: Nitro) { const _cfPagesConfig = nitro.options.cloudflare?.pages || {}; const routes: CloudflarePagesRoutes = { @@ -358,8 +362,15 @@ export async function writeWranglerConfig( ); } else { // Add default compatibility flags - compatFlags.add("nodejs_compat"); - compatFlags.add("no_nodejs_compat_v2"); + if ( + wranglerConfig.compatibility_date && + wranglerConfig.compatibility_date >= NODEJS_COMPAT_SUPPORTED_FROM_DATE + ) { + if (wranglerConfig.compatibility_date < NODEJS_COMPAT_DEFAULT_ON_DATE) { + compatFlags.add("nodejs_compat"); + } + compatFlags.add("no_nodejs_compat_v2"); + } } } wranglerConfig.compatibility_flags = [...compatFlags]; diff --git a/test/unit/cloudflare.utils.test.ts b/test/unit/cloudflare.utils.test.ts new file mode 100644 index 0000000000..f31f79bf1e --- /dev/null +++ b/test/unit/cloudflare.utils.test.ts @@ -0,0 +1,67 @@ +import { mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "pathe"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { writeWranglerConfig } from "../../src/presets/cloudflare/utils"; + +function createNitroStub(compatibilityDate: string) { + const root = mkdtempSync(join(tmpdir(), "nitro-cf-wrangler-")); + return { + root, + nitro: { + options: { + baseURL: "/", + rootDir: root, + workspaceDir: root, + output: { + dir: join(root, ".output"), + serverDir: join(root, ".output/server"), + publicDir: join(root, ".output/public"), + }, + compatibilityDate: { + cloudflare: compatibilityDate, + default: compatibilityDate, + }, + cloudflare: { deployConfig: true, nodeCompat: true }, + }, + logger: { + info: vi.fn(), + warn: vi.fn(), + }, + } as any, + }; +} + +describe("writeWranglerConfig", () => { + let cleanup: string[] = []; + + beforeEach(() => { + cleanup = []; + }); + + afterEach(() => { + for (const dir of cleanup) { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it.each([ + ["2024-09-22", []], + ["2024-09-23", ["nodejs_compat", "no_nodejs_compat_v2"]], + ["2024-09-24", ["nodejs_compat", "no_nodejs_compat_v2"]], + ["2026-08-03", ["nodejs_compat", "no_nodejs_compat_v2"]], + ["2026-08-04", ["no_nodejs_compat_v2"]], + ["2026-08-05", ["no_nodejs_compat_v2"]], + ])( + "uses the required Node.js compatibility flags for compatibility date %s", + async (compatibilityDate, expected) => { + const { root, nitro } = createNitroStub(compatibilityDate); + cleanup.push(root); + await writeWranglerConfig(nitro, "module"); + const config = JSON.parse( + readFileSync(join(root, ".output/server/wrangler.json"), "utf8") + ); + expect(config.compatibility_flags).toEqual(expected); + } + ); +}); From 59cb22d570c8754461682fa7c01374834777a862 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 25 Sep 2026 09:44:17 +0000 Subject: [PATCH 2/3] fix(cloudflare): keep nodejs_compat for dates before 2024-09-23 v2 always sets `no_nodejs_compat_v2`, so `nodejs_compat` (v1) works at any date. Dropping both flags for older or unset compatibility dates left `node:*` imports unresolved at runtime. --- src/presets/cloudflare/utils.ts | 14 +++++--------- test/unit/cloudflare.utils.test.ts | 4 +++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/presets/cloudflare/utils.ts b/src/presets/cloudflare/utils.ts index 31d263a026..e86375363f 100644 --- a/src/presets/cloudflare/utils.ts +++ b/src/presets/cloudflare/utils.ts @@ -24,7 +24,6 @@ import { } from "../_unenv/preset-workerd"; // https://github.com/nitrojs/nitro/issues/4527 -const NODEJS_COMPAT_SUPPORTED_FROM_DATE = "2024-09-23"; const NODEJS_COMPAT_DEFAULT_ON_DATE = "2026-08-04"; export async function writeCFRoutes(nitro: Nitro) { @@ -362,15 +361,12 @@ export async function writeWranglerConfig( ); } else { // Add default compatibility flags - if ( - wranglerConfig.compatibility_date && - wranglerConfig.compatibility_date >= NODEJS_COMPAT_SUPPORTED_FROM_DATE - ) { - if (wranglerConfig.compatibility_date < NODEJS_COMPAT_DEFAULT_ON_DATE) { - compatFlags.add("nodejs_compat"); - } - compatFlags.add("no_nodejs_compat_v2"); + // (`nodejs_compat` is enabled by default from 2026-08-04 and some workerd versions reject it explicitly) + const compatDate = wranglerConfig.compatibility_date; + if (!compatDate || compatDate < NODEJS_COMPAT_DEFAULT_ON_DATE) { + compatFlags.add("nodejs_compat"); } + compatFlags.add("no_nodejs_compat_v2"); } } wranglerConfig.compatibility_flags = [...compatFlags]; diff --git a/test/unit/cloudflare.utils.test.ts b/test/unit/cloudflare.utils.test.ts index f31f79bf1e..0588646c74 100644 --- a/test/unit/cloudflare.utils.test.ts +++ b/test/unit/cloudflare.utils.test.ts @@ -46,7 +46,9 @@ describe("writeWranglerConfig", () => { }); it.each([ - ["2024-09-22", []], + ["", ["nodejs_compat", "no_nodejs_compat_v2"]], + ["2024-04-03", ["nodejs_compat", "no_nodejs_compat_v2"]], + ["2024-09-22", ["nodejs_compat", "no_nodejs_compat_v2"]], ["2024-09-23", ["nodejs_compat", "no_nodejs_compat_v2"]], ["2024-09-24", ["nodejs_compat", "no_nodejs_compat_v2"]], ["2026-08-03", ["nodejs_compat", "no_nodejs_compat_v2"]], From cd26a6ed2d18bfd8db98bd401f18857797957c94 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 25 Sep 2026 11:48:44 +0200 Subject: [PATCH 3/3] Delete test/unit/cloudflare.utils.test.ts --- test/unit/cloudflare.utils.test.ts | 69 ------------------------------ 1 file changed, 69 deletions(-) delete mode 100644 test/unit/cloudflare.utils.test.ts diff --git a/test/unit/cloudflare.utils.test.ts b/test/unit/cloudflare.utils.test.ts deleted file mode 100644 index 0588646c74..0000000000 --- a/test/unit/cloudflare.utils.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { mkdtempSync, readFileSync, rmSync } from "node:fs"; -import { tmpdir } from "node:os"; -import { join } from "pathe"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { writeWranglerConfig } from "../../src/presets/cloudflare/utils"; - -function createNitroStub(compatibilityDate: string) { - const root = mkdtempSync(join(tmpdir(), "nitro-cf-wrangler-")); - return { - root, - nitro: { - options: { - baseURL: "/", - rootDir: root, - workspaceDir: root, - output: { - dir: join(root, ".output"), - serverDir: join(root, ".output/server"), - publicDir: join(root, ".output/public"), - }, - compatibilityDate: { - cloudflare: compatibilityDate, - default: compatibilityDate, - }, - cloudflare: { deployConfig: true, nodeCompat: true }, - }, - logger: { - info: vi.fn(), - warn: vi.fn(), - }, - } as any, - }; -} - -describe("writeWranglerConfig", () => { - let cleanup: string[] = []; - - beforeEach(() => { - cleanup = []; - }); - - afterEach(() => { - for (const dir of cleanup) { - rmSync(dir, { recursive: true, force: true }); - } - }); - - it.each([ - ["", ["nodejs_compat", "no_nodejs_compat_v2"]], - ["2024-04-03", ["nodejs_compat", "no_nodejs_compat_v2"]], - ["2024-09-22", ["nodejs_compat", "no_nodejs_compat_v2"]], - ["2024-09-23", ["nodejs_compat", "no_nodejs_compat_v2"]], - ["2024-09-24", ["nodejs_compat", "no_nodejs_compat_v2"]], - ["2026-08-03", ["nodejs_compat", "no_nodejs_compat_v2"]], - ["2026-08-04", ["no_nodejs_compat_v2"]], - ["2026-08-05", ["no_nodejs_compat_v2"]], - ])( - "uses the required Node.js compatibility flags for compatibility date %s", - async (compatibilityDate, expected) => { - const { root, nitro } = createNitroStub(compatibilityDate); - cleanup.push(root); - await writeWranglerConfig(nitro, "module"); - const config = JSON.parse( - readFileSync(join(root, ".output/server/wrangler.json"), "utf8") - ); - expect(config.compatibility_flags).toEqual(expected); - } - ); -});