Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/fix-vitest-pool-workers-assets-no-dir.md
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
interface Env {
ASSETS: Fetcher;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
async fetch(request): Promise<Response> {
return new Response("Hello from worker!");
},
} satisfies ExportedHandler<Env>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.workerd.json",
"include": ["./**/*.ts"]
}
Original file line number Diff line number Diff line change
@@ -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!");
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.workerd-test.json",
"include": ["./**/*.ts", "../src/env.d.ts"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../tsconfig.node.json",
"include": ["./*.ts"]
}
Original file line number Diff line number Diff line change
@@ -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" },
}),
],
});
Original file line number Diff line number Diff line change
@@ -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",
},
}
40 changes: 26 additions & 14 deletions packages/wrangler/src/api/integrations/platform/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}

Expand Down Expand Up @@ -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 })
: {};
Expand Down
Loading