Skip to content

Commit fdb32ca

Browse files
authored
feat(vite-plugin): allow env override for wrangler config path (#13587)
1 parent 5535ffc commit fdb32ca

4 files changed

Lines changed: 167 additions & 2 deletions

File tree

.changeset/cyan-rivers-happen.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@cloudflare/vite-plugin": patch
3+
---
4+
5+
Allow internal Wrangler config path overrides via env
6+
7+
`@cloudflare/vite-plugin` now checks `CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH` when `configPath` is not set explicitly. This lets integrators provide generated Wrangler configs outside the project root without requiring users to thread `configPath` through framework config.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { mkdir, rm, writeFile } from "node:fs/promises";
2+
import path from "node:path";
3+
import { describe, test } from "vitest";
4+
import { fetchJson, runLongLived, seed, waitForReady } from "./helpers.js";
5+
6+
describe("generated Wrangler config path", () => {
7+
const projectPath = seed("dynamic", { pm: "pnpm" });
8+
9+
test("can serve a Vite app using CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH", async ({
10+
expect,
11+
}) => {
12+
await mkdir(path.join(projectPath, ".generated"), { recursive: true });
13+
await writeFile(
14+
path.join(projectPath, ".generated/wrangler.jsonc"),
15+
JSON.stringify(
16+
{
17+
name: "cloudflare-vite-e2e-generated-config-path",
18+
main: "../src/index.ts",
19+
compatibility_date: "2024-12-30",
20+
compatibility_flags: ["nodejs_compat"],
21+
},
22+
null,
23+
2
24+
)
25+
);
26+
await rm(path.join(projectPath, "wrangler.jsonc"));
27+
28+
const proc = await runLongLived("pnpm", "dev", projectPath, {
29+
CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH: ".generated/wrangler.jsonc",
30+
});
31+
const url = await waitForReady(proc);
32+
33+
expect(await fetchJson(url)).toEqual("OK!");
34+
});
35+
});

packages/vite-plugin-cloudflare/src/__tests__/resolve-plugin-config.spec.ts

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as fs from "node:fs";
22
import * as os from "node:os";
33
import * as path from "node:path";
44
import { removeDirSync } from "@cloudflare/workers-utils";
5-
import { afterEach, assert, beforeEach, describe, test } from "vitest";
5+
import { afterEach, assert, beforeEach, describe, test, vi } from "vitest";
66
import { resolvePluginConfig } from "../plugin-config";
77
import type {
88
AssetsOnlyResolvedConfig,
@@ -588,6 +588,127 @@ describe("resolvePluginConfig - zero-config mode", () => {
588588
});
589589
});
590590

591+
describe("resolvePluginConfig - internal config path env fallback", () => {
592+
let tempDir: string;
593+
let originalConfigPathEnvVar: string | undefined;
594+
595+
beforeEach(() => {
596+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "vite-plugin-test-"));
597+
originalConfigPathEnvVar = process.env.CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH;
598+
});
599+
600+
afterEach(() => {
601+
vi.unstubAllEnvs();
602+
if (originalConfigPathEnvVar === undefined) {
603+
delete process.env.CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH;
604+
} else {
605+
process.env.CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH =
606+
originalConfigPathEnvVar;
607+
}
608+
removeDirSync(tempDir);
609+
});
610+
611+
const viteEnv = { mode: "development", command: "serve" as const };
612+
613+
function createWorkerConfig(dir: string, name: string) {
614+
const configPath = path.join(dir, "wrangler.jsonc");
615+
fs.mkdirSync(path.join(dir, "src"), { recursive: true });
616+
fs.writeFileSync(
617+
configPath,
618+
JSON.stringify({
619+
name,
620+
main: "./src/index.ts",
621+
compatibility_date: "2024-01-01",
622+
})
623+
);
624+
fs.writeFileSync(path.join(dir, "src/index.ts"), "export default {}");
625+
return configPath;
626+
}
627+
628+
test("should resolve entry worker config from CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH loaded from env files", ({
629+
expect,
630+
}) => {
631+
const hiddenConfigPath = createWorkerConfig(
632+
path.join(tempDir, ".sst"),
633+
"hidden-worker"
634+
);
635+
fs.writeFileSync(
636+
path.join(tempDir, ".env.development"),
637+
"CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH=.sst/wrangler.jsonc\n"
638+
);
639+
640+
const result = resolvePluginConfig(
641+
{},
642+
{ root: tempDir },
643+
viteEnv
644+
) as WorkersResolvedConfig;
645+
646+
expect(result.type).toBe("workers");
647+
const entryWorker = result.environmentNameToWorkerMap.get(
648+
result.entryWorkerEnvironmentName
649+
);
650+
assert(entryWorker);
651+
expect(entryWorker.config.name).toBe("hidden-worker");
652+
expect(entryWorker.config.main).toBe(
653+
path.join(tempDir, ".sst", "src/index.ts")
654+
);
655+
expect([...result.configPaths]).toEqual([hiddenConfigPath]);
656+
});
657+
658+
test("should prefer CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH over auto-discovered config", ({
659+
expect,
660+
}) => {
661+
createWorkerConfig(tempDir, "root-worker");
662+
const hiddenConfigPath = createWorkerConfig(
663+
path.join(tempDir, ".sst"),
664+
"hidden-worker"
665+
);
666+
vi.stubEnv("CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH", ".sst/wrangler.jsonc");
667+
668+
const result = resolvePluginConfig(
669+
{},
670+
{ root: tempDir },
671+
viteEnv
672+
) as WorkersResolvedConfig;
673+
674+
expect(result.type).toBe("workers");
675+
const entryWorker = result.environmentNameToWorkerMap.get(
676+
result.entryWorkerEnvironmentName
677+
);
678+
assert(entryWorker);
679+
expect(entryWorker.config.name).toBe("hidden-worker");
680+
expect([...result.configPaths]).toEqual([hiddenConfigPath]);
681+
});
682+
683+
test("should prefer explicit configPath over CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH", ({
684+
expect,
685+
}) => {
686+
createWorkerConfig(path.join(tempDir, ".sst"), "hidden-worker");
687+
const explicitConfigPath = createWorkerConfig(
688+
path.join(tempDir, "visible"),
689+
"explicit-worker"
690+
);
691+
vi.stubEnv("CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH", ".sst/wrangler.jsonc");
692+
693+
const result = resolvePluginConfig(
694+
{ configPath: explicitConfigPath },
695+
{ root: tempDir },
696+
viteEnv
697+
) as WorkersResolvedConfig;
698+
699+
expect(result.type).toBe("workers");
700+
const entryWorker = result.environmentNameToWorkerMap.get(
701+
result.entryWorkerEnvironmentName
702+
);
703+
assert(entryWorker);
704+
expect(entryWorker.config.name).toBe("explicit-worker");
705+
expect(entryWorker.config.main).toBe(
706+
path.join(tempDir, "visible", "src/index.ts")
707+
);
708+
expect([...result.configPaths]).toEqual([explicitConfigPath]);
709+
});
710+
});
711+
591712
describe("resolvePluginConfig - defaults fill in missing fields", () => {
592713
let tempDir: string;
593714

packages/vite-plugin-cloudflare/src/plugin-config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,11 @@ export function resolvePluginConfig(
298298
const configPaths = new Set<string>();
299299
const cloudflareEnv = prefixedEnv.CLOUDFLARE_ENV;
300300
const validateAndAddEnvironmentName = createEnvironmentNameValidator();
301+
const requestedEntryWorkerConfigPath =
302+
pluginConfig.configPath ?? prefixedEnv.CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH;
301303
const configPath = getValidatedWranglerConfigPath(
302304
root,
303-
pluginConfig.configPath
305+
requestedEntryWorkerConfigPath
304306
);
305307

306308
// Build entry worker config: defaults → file config → config()

0 commit comments

Comments
 (0)