From 729d8403a5f28390112e5327dbed4b4bc6506609 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 11 May 2026 00:15:18 +0100 Subject: [PATCH] fix(cloudflare): omit worker entry from wrangler.json for static builds --- src/presets/cloudflare/utils.ts | 32 ++++++++----- test/unit/cloudflare.utils.test.ts | 72 ++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 11 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 64c656f419..92e5b1448b 100644 --- a/src/presets/cloudflare/utils.ts +++ b/src/presets/cloudflare/utils.ts @@ -228,17 +228,27 @@ export async function writeWranglerConfig(nitro: Nitro, cfTarget: "pages" | "mod overrides.pages_build_output_dir = relative(wranglerConfigDir, nitro.options.output.dir); } else { // Modules - overrides.main = relative(wranglerConfigDir, join(nitro.options.output.serverDir, "index.mjs")); - overrides.assets = { - binding: "ASSETS", - directory: relative( + const assetsDirectory = relative( + wranglerConfigDir, + resolve( + nitro.options.output.publicDir, + "..".repeat(nitro.options.baseURL.split("/").filter(Boolean).length) + ) + ); + if (nitro.options.static) { + // No worker script is emitted; `main` and `assets.binding` only apply + // when there is one. https://developers.cloudflare.com/workers/static-assets/ + overrides.assets = { directory: assetsDirectory }; + } else { + overrides.main = relative( wranglerConfigDir, - resolve( - nitro.options.output.publicDir, - "..".repeat(nitro.options.baseURL.split("/").filter(Boolean).length) - ) - ), - }; + join(nitro.options.output.serverDir, "index.mjs") + ); + overrides.assets = { + binding: "ASSETS", + directory: assetsDirectory, + }; + } } // Read user config @@ -274,7 +284,7 @@ export async function writeWranglerConfig(nitro: Nitro, cfTarget: "pages" | "mod wranglerConfig.compatibility_flags.push("nodejs_compat"); } - if (cfTarget === "module") { + if (cfTarget === "module" && !nitro.options.static) { // Avoid double bundling if (wranglerConfig.no_bundle === undefined) { wranglerConfig.no_bundle = true; diff --git a/test/unit/cloudflare.utils.test.ts b/test/unit/cloudflare.utils.test.ts new file mode 100644 index 0000000000..74e5c14004 --- /dev/null +++ b/test/unit/cloudflare.utils.test.ts @@ -0,0 +1,72 @@ +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.ts"; + +function createNitroStub(overrides: { static?: boolean } = {}) { + const root = mkdtempSync(join(tmpdir(), "nitro-cf-wrangler-")); + return { + root, + nitro: { + options: { + static: overrides.static ?? false, + baseURL: "/", + rootDir: root, + workspaceDir: root, + output: { + dir: join(root, ".output"), + serverDir: join(root, ".output/server"), + publicDir: join(root, ".output/public"), + }, + compatibilityDate: { cloudflare: "2025-10-24", default: "2025-10-24" }, + cloudflare: { deployConfig: true, nodeCompat: true }, + experimental: {}, + scheduledTasks: {}, + }, + logger: { + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + success: vi.fn(), + }, + } as any, + }; +} + +describe("writeWranglerConfig (cloudflare-module)", () => { + let cleanup: string[] = []; + beforeEach(() => { + cleanup = []; + }); + afterEach(() => { + for (const dir of cleanup) { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it("emits main and ASSETS binding for a normal (non-static) build", async () => { + const { root, nitro } = createNitroStub({ static: false }); + cleanup.push(root); + await writeWranglerConfig(nitro, "module"); + const config = JSON.parse(readFileSync(join(root, ".output/server/wrangler.json"), "utf8")); + expect(config.main).toBe("index.mjs"); + expect(config.assets).toEqual({ binding: "ASSETS", directory: "../public" }); + expect(config.no_bundle).toBe(true); + expect(config.rules).toEqual([{ type: "ESModule", globs: ["**/*.mjs", "**/*.js"] }]); + }); + + it("omits main, ASSETS binding and module bundling rules for a static build", async () => { + // Regression test for nuxt/nuxt#34186 — `nuxt generate` (which sets + // `nitro.options.static = true`) targeting cloudflare_module previously + // wrote a wrangler.json pointing at a non-existent index.mjs. + const { root, nitro } = createNitroStub({ static: true }); + cleanup.push(root); + await writeWranglerConfig(nitro, "module"); + const config = JSON.parse(readFileSync(join(root, ".output/server/wrangler.json"), "utf8")); + expect(config.main).toBeUndefined(); + expect(config.assets).toEqual({ directory: "../public" }); + expect(config.no_bundle).toBeUndefined(); + expect(config.rules).toBeUndefined(); + }); +});