From 9b3bc685b9e355ac1c07b16c98ebf657088f8eee Mon Sep 17 00:00:00 2001 From: Samuel Macleod Date: Thu, 26 Mar 2026 23:32:38 +0000 Subject: [PATCH] [wrangler] Fix vitest-pool-workers crashing when assets configured without directory --- .../fix-vitest-pool-workers-assets-no-dir.md | 7 ++++ .../workers-assets-no-dir/src/env.d.ts | 3 ++ .../workers-assets-no-dir/src/index.ts | 5 +++ .../workers-assets-no-dir/src/tsconfig.json | 4 ++ .../test/assets-no-dir.test.ts | 19 +++++++++ .../workers-assets-no-dir/test/tsconfig.json | 4 ++ .../workers-assets-no-dir/tsconfig.json | 4 ++ .../workers-assets-no-dir/vitest.config.ts | 10 +++++ .../workers-assets-no-dir/wrangler.jsonc | 10 +++++ .../src/api/integrations/platform/index.ts | 40 ++++++++++++------- 10 files changed, 92 insertions(+), 14 deletions(-) create mode 100644 .changeset/fix-vitest-pool-workers-assets-no-dir.md create mode 100644 fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/env.d.ts create mode 100644 fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/index.ts create mode 100644 fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/tsconfig.json create mode 100644 fixtures/vitest-pool-workers-examples/workers-assets-no-dir/test/assets-no-dir.test.ts create mode 100644 fixtures/vitest-pool-workers-examples/workers-assets-no-dir/test/tsconfig.json create mode 100644 fixtures/vitest-pool-workers-examples/workers-assets-no-dir/tsconfig.json create mode 100644 fixtures/vitest-pool-workers-examples/workers-assets-no-dir/vitest.config.ts create mode 100644 fixtures/vitest-pool-workers-examples/workers-assets-no-dir/wrangler.jsonc diff --git a/.changeset/fix-vitest-pool-workers-assets-no-dir.md b/.changeset/fix-vitest-pool-workers-assets-no-dir.md new file mode 100644 index 0000000000..408189b2d2 --- /dev/null +++ b/.changeset/fix-vitest-pool-workers-assets-no-dir.md @@ -0,0 +1,7 @@ +--- +"wrangler": patch +--- + +Fix `getPlatformProxy` and `unstable_getMiniflareWorkerOptions` crashing when `assets` is configured without a `directory` + +`getPlatformProxy` and `unstable_getMiniflareWorkerOptions` now skip asset setup when the config has an `assets` block but no `directory` — instead of throwing "missing required `directory` property". This happens when an external tool like `@cloudflare/vite-plugin` handles asset serving independently. diff --git a/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/env.d.ts b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/env.d.ts new file mode 100644 index 0000000000..079bf105b5 --- /dev/null +++ b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/env.d.ts @@ -0,0 +1,3 @@ +interface Env { + ASSETS: Fetcher; +} diff --git a/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/index.ts b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/index.ts new file mode 100644 index 0000000000..eefdc49290 --- /dev/null +++ b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/index.ts @@ -0,0 +1,5 @@ +export default { + async fetch(request): Promise { + return new Response("Hello from worker!"); + }, +} satisfies ExportedHandler; diff --git a/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/tsconfig.json b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/tsconfig.json new file mode 100644 index 0000000000..0141323e2f --- /dev/null +++ b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/src/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.workerd.json", + "include": ["./**/*.ts"] +} diff --git a/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/test/assets-no-dir.test.ts b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/test/assets-no-dir.test.ts new file mode 100644 index 0000000000..1a5791cca7 --- /dev/null +++ b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/test/assets-no-dir.test.ts @@ -0,0 +1,19 @@ +import { SELF } from "cloudflare:test"; +import { describe, it } from "vitest"; + +// Regression test for https://github.com/cloudflare/workers-sdk/issues/9381 +// +// When a wrangler config has `assets: { binding: "ASSETS" }` but no `directory` +// (as is common when using @cloudflare/vite-plugin, which handles asset serving +// independently via its dev server), vitest-pool-workers must not throw: +// "The `assets` property in your configuration is missing the required `directory` property." + +describe("workers-assets-no-dir", () => { + it("worker starts and responds when assets binding has no directory configured", async ({ + expect, + }) => { + const response = await SELF.fetch("http://example.com/"); + expect(response.status).toBe(200); + expect(await response.text()).toBe("Hello from worker!"); + }); +}); diff --git a/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/test/tsconfig.json b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/test/tsconfig.json new file mode 100644 index 0000000000..49d66320ea --- /dev/null +++ b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/test/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.workerd-test.json", + "include": ["./**/*.ts", "../src/env.d.ts"] +} diff --git a/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/tsconfig.json b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/tsconfig.json new file mode 100644 index 0000000000..90e58bf03e --- /dev/null +++ b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig.node.json", + "include": ["./*.ts"] +} diff --git a/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/vitest.config.ts b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/vitest.config.ts new file mode 100644 index 0000000000..9b79788edd --- /dev/null +++ b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/vitest.config.ts @@ -0,0 +1,10 @@ +import { cloudflareTest } from "@cloudflare/vitest-pool-workers"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + plugins: [ + cloudflareTest({ + wrangler: { configPath: "./wrangler.jsonc" }, + }), + ], +}); diff --git a/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/wrangler.jsonc b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/wrangler.jsonc new file mode 100644 index 0000000000..49d877d6b1 --- /dev/null +++ b/fixtures/vitest-pool-workers-examples/workers-assets-no-dir/wrangler.jsonc @@ -0,0 +1,10 @@ +{ + "name": "workers-assets-no-directory", + "main": "src/index.ts", + // Simulate a project using @cloudflare/vite-plugin where assets are configured + // with a binding but no directory (vite-plugin serves them via its dev server). + // vitest-pool-workers must not throw "missing required `directory` property" here. + "assets": { + "binding": "ASSETS", + }, +} diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 3f3f0cc617..ba3e336574 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -267,15 +267,19 @@ async function getMiniflareOptionsFromConfig(args: { let processedAssetOptions: AssetsOptions | undefined; - try { - processedAssetOptions = getAssetsOptions({ assets: undefined }, config); - } catch (e) { - const isNonExistentError = e instanceof NonExistentAssetsDirError; - // we want to loosen up the assets directory existence restriction here, - // since `getPlatformProxy` can be run when the assets directory doesn't actual - // exist, but all other exceptions should still be thrown - if (!isNonExistentError) { - throw e; + // Only resolve assets if a directory is configured. When assets are configured + // without a directory (e.g. via @cloudflare/vite-plugin), skip asset setup. + if (config.assets?.directory) { + try { + processedAssetOptions = getAssetsOptions({ assets: undefined }, config); + } catch (e) { + const isNonExistentError = e instanceof NonExistentAssetsDirError; + // we want to loosen up the assets directory existence restriction here, + // since `getPlatformProxy` can be run when the assets directory doesn't + // actually exist, but all other exceptions should still be thrown + if (!isNonExistentError) { + throw e; + } } } @@ -499,11 +503,19 @@ export function unstable_getMiniflareWorkerOptions( const sitesAssetPaths = getSiteAssetPaths(config); const sitesOptions = buildSitesOptions({ legacyAssetPaths: sitesAssetPaths }); - const processedAssetOptions = getAssetsOptions( - { assets: undefined }, - config, - options?.overrides?.assets - ); + // Only resolve assets if a directory is available (from config or overrides). + // When assets are configured without a directory (e.g. when using + // @cloudflare/vite-plugin, which handles asset serving independently), + // there's nothing for Miniflare to serve, so skip asset setup entirely. + const hasAssetsDirectory = + config.assets?.directory || options?.overrides?.assets?.directory; + const processedAssetOptions = hasAssetsDirectory + ? getAssetsOptions( + { assets: undefined }, + config, + options?.overrides?.assets + ) + : undefined; const assetOptions = processedAssetOptions ? buildAssetOptions({ assets: processedAssetOptions }) : {};