From e459bf89b92bbbdc1e3bddf14ba887c447de6340 Mon Sep 17 00:00:00 2001 From: James Opstad <13586373+jamesopstad@users.noreply.github.com> Date: Thu, 31 Jul 2025 21:27:11 +0100 Subject: [PATCH 1/3] Add failing test --- .../server-headers/react-spa.spec.ts | 19 +++++++++++++++++++ .../playground/react-spa/package.json | 1 + .../react-spa/vite.config.server-headers.ts | 12 ++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 packages/vite-plugin-cloudflare/playground/react-spa/__tests__/server-headers/react-spa.spec.ts create mode 100644 packages/vite-plugin-cloudflare/playground/react-spa/vite.config.server-headers.ts diff --git a/packages/vite-plugin-cloudflare/playground/react-spa/__tests__/server-headers/react-spa.spec.ts b/packages/vite-plugin-cloudflare/playground/react-spa/__tests__/server-headers/react-spa.spec.ts new file mode 100644 index 000000000000..90c34a72e006 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/react-spa/__tests__/server-headers/react-spa.spec.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from "vitest"; +import { getResponse, isBuild } from "../../../__test-utils__"; + +describe.runIf(!isBuild)( + "adds headers included in `server.headers` to asset responses", + () => { + test("adds headers to HTML responses", async () => { + const response = await getResponse(); + const customHeader = await response.headerValue("custom-header"); + expect(customHeader).toBe("custom-value"); + }); + + test("adds headers to non-HTML responses", async () => { + const response = await getResponse("/vite.svg"); + const customHeader = await response.headerValue("custom-header"); + expect(customHeader).toBe("custom-value"); + }); + } +); diff --git a/packages/vite-plugin-cloudflare/playground/react-spa/package.json b/packages/vite-plugin-cloudflare/playground/react-spa/package.json index eea6e702929d..364778ec5c76 100644 --- a/packages/vite-plugin-cloudflare/playground/react-spa/package.json +++ b/packages/vite-plugin-cloudflare/playground/react-spa/package.json @@ -6,6 +6,7 @@ "build": "vite build --app", "check:types": "tsc --build", "dev": "vite dev", + "dev:server-headers": "vite dev -c ./vite.config.server-headers.ts", "preview": "vite preview" }, "dependencies": { diff --git a/packages/vite-plugin-cloudflare/playground/react-spa/vite.config.server-headers.ts b/packages/vite-plugin-cloudflare/playground/react-spa/vite.config.server-headers.ts new file mode 100644 index 000000000000..349e1063720c --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/react-spa/vite.config.server-headers.ts @@ -0,0 +1,12 @@ +import { cloudflare } from "@cloudflare/vite-plugin"; +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vite"; + +export default defineConfig({ + server: { + headers: { + "custom-header": "custom-value", + }, + }, + plugins: [react(), cloudflare({ inspectorPort: false, persistState: false })], +}); From 78360da657a1a9760d06e51ded5bc41bbf4ea13d Mon Sep 17 00:00:00 2001 From: James Opstad <13586373+jamesopstad@users.noreply.github.com> Date: Fri, 1 Aug 2025 09:53:29 +0100 Subject: [PATCH 2/3] Add headers set via to asset responses --- .../__tests__/server-headers/react-spa.spec.ts | 18 +++++++++++++----- .../react-spa/vite.config.server-headers.ts | 4 +++- .../src/asset-workers/asset-worker.ts | 16 ++++++++++++++++ .../src/miniflare-options.ts | 1 + 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/packages/vite-plugin-cloudflare/playground/react-spa/__tests__/server-headers/react-spa.spec.ts b/packages/vite-plugin-cloudflare/playground/react-spa/__tests__/server-headers/react-spa.spec.ts index 90c34a72e006..801b9b948168 100644 --- a/packages/vite-plugin-cloudflare/playground/react-spa/__tests__/server-headers/react-spa.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/react-spa/__tests__/server-headers/react-spa.spec.ts @@ -2,18 +2,26 @@ import { describe, expect, test } from "vitest"; import { getResponse, isBuild } from "../../../__test-utils__"; describe.runIf(!isBuild)( - "adds headers included in `server.headers` to asset responses", + "adds headers included in Vite's `server.headers` to asset responses in dev", () => { test("adds headers to HTML responses", async () => { const response = await getResponse(); - const customHeader = await response.headerValue("custom-header"); - expect(customHeader).toBe("custom-value"); + const headers = await response.allHeaders(); + expect(headers).toMatchObject({ + "custom-string": "string-value", + "custom-string-array": "one, two, three", + "custom-number": "123", + }); }); test("adds headers to non-HTML responses", async () => { const response = await getResponse("/vite.svg"); - const customHeader = await response.headerValue("custom-header"); - expect(customHeader).toBe("custom-value"); + const headers = await response.allHeaders(); + expect(headers).toMatchObject({ + "custom-string": "string-value", + "custom-string-array": "one, two, three", + "custom-number": "123", + }); }); } ); diff --git a/packages/vite-plugin-cloudflare/playground/react-spa/vite.config.server-headers.ts b/packages/vite-plugin-cloudflare/playground/react-spa/vite.config.server-headers.ts index 349e1063720c..af5e31a26bf0 100644 --- a/packages/vite-plugin-cloudflare/playground/react-spa/vite.config.server-headers.ts +++ b/packages/vite-plugin-cloudflare/playground/react-spa/vite.config.server-headers.ts @@ -5,7 +5,9 @@ import { defineConfig } from "vite"; export default defineConfig({ server: { headers: { - "custom-header": "custom-value", + "custom-string": "string-value", + "custom-string-array": ["one", "two", "three"], + "custom-number": 123, }, }, plugins: [react(), cloudflare({ inspectorPort: false, persistState: false })], diff --git a/packages/vite-plugin-cloudflare/src/asset-workers/asset-worker.ts b/packages/vite-plugin-cloudflare/src/asset-workers/asset-worker.ts index 14a2588625a7..13dce2db267f 100644 --- a/packages/vite-plugin-cloudflare/src/asset-workers/asset-worker.ts +++ b/packages/vite-plugin-cloudflare/src/asset-workers/asset-worker.ts @@ -1,10 +1,12 @@ import AssetWorker from "@cloudflare/workers-shared/asset-worker"; import { UNKNOWN_HOST } from "../shared"; import type { Env as _Env } from "@cloudflare/workers-shared/asset-worker"; +import type { ResolvedConfig } from "vite"; interface Env extends _Env { __VITE_HTML_EXISTS__: Fetcher; __VITE_FETCH_HTML__: Fetcher; + __VITE_HEADERS__: string; } export default class CustomAssetWorker extends AssetWorker { @@ -13,6 +15,20 @@ export default class CustomAssetWorker extends AssetWorker { const modifiedResponse = new Response(response.body, response); modifiedResponse.headers.delete("ETag"); modifiedResponse.headers.delete("Cache-Control"); + // Add headers set via `server.headers` in the Vite config + const viteHeaders = JSON.parse( + this.env.__VITE_HEADERS__ + ) as ResolvedConfig["server"]["headers"]; + + for (const [key, value] of Object.entries(viteHeaders)) { + if (Array.isArray(value)) { + for (const item of value) { + modifiedResponse.headers.append(key, item); + } + } else if (value !== undefined) { + modifiedResponse.headers.set(key, String(value)); + } + } return modifiedResponse; } diff --git a/packages/vite-plugin-cloudflare/src/miniflare-options.ts b/packages/vite-plugin-cloudflare/src/miniflare-options.ts index a1be6e0fc842..c5603fc23b66 100644 --- a/packages/vite-plugin-cloudflare/src/miniflare-options.ts +++ b/packages/vite-plugin-cloudflare/src/miniflare-options.ts @@ -292,6 +292,7 @@ export async function getDevMiniflareOptions(config: { ], bindings: { CONFIG: assetsConfig, + __VITE_HEADERS__: JSON.stringify(viteDevServer.config.server.headers), }, serviceBindings: { __VITE_HTML_EXISTS__: async (request) => { From 64ccf9582b43a18f4ec86caf90a4b1425e3e01c6 Mon Sep 17 00:00:00 2001 From: James Opstad <13586373+jamesopstad@users.noreply.github.com> Date: Fri, 1 Aug 2025 09:55:08 +0100 Subject: [PATCH 3/3] Add changeset --- .changeset/shaky-experts-beg.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/shaky-experts-beg.md diff --git a/.changeset/shaky-experts-beg.md b/.changeset/shaky-experts-beg.md new file mode 100644 index 000000000000..0b4b7e625a32 --- /dev/null +++ b/.changeset/shaky-experts-beg.md @@ -0,0 +1,5 @@ +--- +"@cloudflare/vite-plugin": patch +--- + +Ensure that headers set via `server.headers` in the Vite config are added to HTML asset responses in development.