From 72946da57a6383bd25a654f4ae402b66fee6e260 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 19 May 2025 12:01:28 +0100 Subject: [PATCH 01/42] Implement .env support in local development --- packages/wrangler/e2e/dev.test.ts | 248 ++++++ packages/wrangler/e2e/startWorker.test.ts | 796 +++++++++++------- packages/wrangler/package.json | 1 + packages/wrangler/src/__tests__/dev.test.ts | 238 +++++- .../src/__tests__/type-generation.test.ts | 55 ++ packages/wrangler/src/config/dot-env.ts | 71 ++ packages/wrangler/src/config/index.ts | 44 - packages/wrangler/src/dev/dev-vars.ts | 70 +- .../src/environment-variables/factory.ts | 3 +- .../environment-variables/misc-variables.ts | 9 + packages/wrangler/src/index.ts | 15 +- pnpm-lock.yaml | 17 + 12 files changed, 1161 insertions(+), 406 deletions(-) create mode 100644 packages/wrangler/src/config/dot-env.ts diff --git a/packages/wrangler/e2e/dev.test.ts b/packages/wrangler/e2e/dev.test.ts index 012cbdd80d1f..eb4e33df710e 100644 --- a/packages/wrangler/e2e/dev.test.ts +++ b/packages/wrangler/e2e/dev.test.ts @@ -2294,3 +2294,251 @@ This is a random email body. `); }); }); + +describe(".env support in local dev", () => { + const seedFiles = { + "wrangler.jsonc": JSON.stringify({ + name: workerName, + main: "src/index.ts", + compatibility_date: "2025-07-01", + vars: { + WRANGLER_ENV_VAR_0: "default-0", + WRANGLER_ENV_VAR_1: "default-1", + WRANGLER_ENV_VAR_2: "default-2", + WRANGLER_ENV_VAR_3: "default-3", + }, + }), + "src/index.ts": dedent` + export default { + fetch(request, env) { + return new Response(JSON.stringify(env, null, 2)); + } + } + `, + }; + + it("should load environment variables from .env file", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed(seedFiles); + await helper.seed({ + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + }); + + const worker = helper.runLongLived("wrangler dev"); + const { url } = await worker.waitForReady(); + expect(await (await fetch(url)).text()).toMatchInlineSnapshot(` + "{ + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "env-1", + "WRANGLER_ENV_VAR_2": "env-2", + "WRANGLER_ENV_VAR_3": "default-3" + }" + `); + }); + + it("should not load load environment variables from .env files if there is a .dev.vars file", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed(seedFiles); + await helper.seed({ + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + }); + await helper.seed({ + ".dev.vars": dedent` + WRANGLER_ENV_VAR_1=dev-vars-1 + WRANGLER_ENV_VAR_2=dev-vars-2 + `, + }); + + const worker = helper.runLongLived("wrangler dev"); + const { url } = await worker.waitForReady(); + expect(await (await fetch(url)).text()).toMatchInlineSnapshot(` + "{ + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "dev-vars-1", + "WRANGLER_ENV_VAR_2": "dev-vars-2", + "WRANGLER_ENV_VAR_3": "default-3" + }" + `); + }); + + it("should load environment variables from .env.staging if it exists and --env=staging", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed(seedFiles); + await helper.seed({ + ".env.staging": dedent` + WRANGLER_ENV_VAR_2=staging-2 + WRANGLER_ENV_VAR_3=staging-3 + `, + }); + + const worker = helper.runLongLived("wrangler dev --env=staging"); + const { url } = await worker.waitForReady(); + expect(await (await fetch(url)).text()).toMatchInlineSnapshot(` + "{ + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "default-1", + "WRANGLER_ENV_VAR_2": "staging-2", + "WRANGLER_ENV_VAR_3": "staging-3" + }" + `); + }); + + it("should prefer to load environment variables from .env.staging over .env, if --env=staging", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed(seedFiles); + await helper.seed({ + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + }); + await helper.seed({ + ".env.staging": dedent` + WRANGLER_ENV_VAR_2=staging-2 + WRANGLER_ENV_VAR_3=staging-3 + `, + }); + + const worker = helper.runLongLived("wrangler dev --env=staging"); + const { url } = await worker.waitForReady(); + expect(await (await fetch(url)).text()).toMatchInlineSnapshot(` + "{ + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "env-1", + "WRANGLER_ENV_VAR_2": "staging-2", + "WRANGLER_ENV_VAR_3": "staging-3" + }" + `); + }); + + it("should load environment variables from .env file if --env=xxx and .env.xxx does not exist", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed(seedFiles); + await helper.seed({ + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + }); + await helper.seed({ + ".env.staging": dedent` + WRANGLER_ENV_VAR_2=staging-2 + WRANGLER_ENV_VAR_3=staging-3 + `, + }); + + const worker = helper.runLongLived("wrangler dev --env=xxx"); + const { url } = await worker.waitForReady(); + expect(await (await fetch(url)).text()).toMatchInlineSnapshot(` + "{ + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "env-1", + "WRANGLER_ENV_VAR_2": "env-2", + "WRANGLER_ENV_VAR_3": "default-3" + }" + `); + }); + + it("should prefer to load environment variables from .env.local over .env", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed(seedFiles); + await helper.seed({ + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + }); + await helper.seed({ + ".env.local": dedent` + WRANGLER_ENV_VAR_2=local-2 + WRANGLER_ENV_VAR_3=local-3 + `, + }); + + const worker = helper.runLongLived("wrangler dev"); + const { url } = await worker.waitForReady(); + expect(await (await fetch(url)).text()).toMatchInlineSnapshot(` + "{ + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "env-1", + "WRANGLER_ENV_VAR_2": "local-2", + "WRANGLER_ENV_VAR_3": "local-3" + }" + `); + }); + + it("should prefer to load environment variables from .env.staging.local over .env.staging, etc", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed(seedFiles); + await helper.seed({ + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + }); + await helper.seed({ + ".env.local": dedent` + WRANGLER_ENV_VAR_2=local-2 + WRANGLER_ENV_VAR_3=local-3 + `, + }); + await helper.seed({ + ".env.staging": dedent` + WRANGLER_ENV_VAR_3=staging-3 + WRANGLER_ENV_VAR_4=staging-4 + `, + }); + await helper.seed({ + ".env.staging.local": dedent` + WRANGLER_ENV_VAR_4=staging-local-4 + WRANGLER_ENV_VAR_5=staging-local-5 + `, + }); + + const worker = helper.runLongLived("wrangler dev --env=staging"); + const { url } = await worker.waitForReady(); + expect(await (await fetch(url)).text()).toMatchInlineSnapshot(` + "{ + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "env-1", + "WRANGLER_ENV_VAR_2": "local-2", + "WRANGLER_ENV_VAR_3": "staging-3", + "WRANGLER_ENV_VAR_4": "staging-local-4", + "WRANGLER_ENV_VAR_5": "staging-local-5" + }" + `); + }); + + it("should load environment variables from process.env if CLOUDFLARE_INCLUDE_PROCESS_ENV is true", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed(seedFiles); + await helper.seed({ + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + }); + + const worker = helper.runLongLived("wrangler dev", { + env: { CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", ...process.env }, + }); + const { url } = await worker.waitForReady(); + // We could dump out all the bindings but that would be a lot of noise, and also may change between OSes and runs. + // Instead, we know that the `CLOUDFLARE_INCLUDE_PROCESS_ENV` variable should be present, so we just check for that. + expect(await (await fetch(url)).text()).contains( + '"CLOUDFLARE_INCLUDE_PROCESS_ENV": "true"' + ); + expect(await (await fetch(url)).text()).contains( + '"WRANGLER_ENV_VAR_0": "default-0"' + ); + expect(await (await fetch(url)).text()).contains( + '"WRANGLER_ENV_VAR_1": "env-1"' + ); + }); +}); diff --git a/packages/wrangler/e2e/startWorker.test.ts b/packages/wrangler/e2e/startWorker.test.ts index db6a32a2fdd4..3fdd2adb42be 100644 --- a/packages/wrangler/e2e/startWorker.test.ts +++ b/packages/wrangler/e2e/startWorker.test.ts @@ -44,7 +44,7 @@ function collectMessagesContaining( return collection; } -describe.each(OPTIONS)("DevEnv (remote: $remote)", ({ remote }) => { +describe("DevEnv", () => { let helper: WranglerE2ETestHelper; let wrangler: Wrangler; let startWorker: Wrangler["unstable_startWorker"]; @@ -54,10 +54,11 @@ describe.each(OPTIONS)("DevEnv (remote: $remote)", ({ remote }) => { startWorker = wrangler.unstable_startWorker; }); - it("ProxyWorker buffers requests while runtime reloads", async (t) => { - t.onTestFinished(() => worker?.dispose()); + describe.each(OPTIONS)("(remote: $remote)", ({ remote }) => { + it("ProxyWorker buffers requests while runtime reloads", async (t) => { + t.onTestFinished(() => worker?.dispose()); - const script = dedent` + const script = dedent` export default { fetch() { return new Response("body:1"); @@ -65,32 +66,32 @@ describe.each(OPTIONS)("DevEnv (remote: $remote)", ({ remote }) => { } `; - await helper.seed({ - "src/index.ts": script, - }); + await helper.seed({ + "src/index.ts": script, + }); - const worker = await startWorker({ - entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), + const worker = await startWorker({ + entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), - dev: { remote }, - }); + dev: { remote }, + }); - let res = await worker.fetch("http://dummy"); - await expect(res.text()).resolves.toBe("body:1"); + let res = await worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:1"); - await helper.seed({ - "src/index.ts": script.replace("body:1", "body:2"), - }); - await setTimeout(300); + await helper.seed({ + "src/index.ts": script.replace("body:1", "body:2"), + }); + await setTimeout(300); - res = await worker.fetch("http://dummy"); - await expect(res.text()).resolves.toBe("body:2"); - }); + res = await worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:2"); + }); - it("InspectorProxyWorker discovery endpoints + devtools websocket connection", async (t) => { - t.onTestFinished(() => worker?.dispose()); + it("InspectorProxyWorker discovery endpoints + devtools websocket connection", async (t) => { + t.onTestFinished(() => worker?.dispose()); - const script = dedent` + const script = dedent` export default { fetch() { console.log('Inside mock user worker'); @@ -100,130 +101,132 @@ describe.each(OPTIONS)("DevEnv (remote: $remote)", ({ remote }) => { } `; - await helper.seed({ - "src/index.ts": script, - }); + await helper.seed({ + "src/index.ts": script, + }); - const worker = await startWorker({ - name: "test-worker", - entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), + const worker = await startWorker({ + name: "test-worker", + entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), - dev: { remote }, - }); + dev: { remote }, + }); - const inspectorUrl = await worker.inspectorUrl; - assert(inspectorUrl, "missing inspectorUrl"); - const res = await undici.fetch(`http://${inspectorUrl.host}/json`); + const inspectorUrl = await worker.inspectorUrl; + assert(inspectorUrl, "missing inspectorUrl"); + const res = await undici.fetch(`http://${inspectorUrl.host}/json`); - await expect(res.json()).resolves.toBeInstanceOf(Array); + await expect(res.json()).resolves.toBeInstanceOf(Array); - assert(inspectorUrl, "missing inspectorUrl"); - const ws = new WebSocket(inspectorUrl.href); - const openPromise = events.once(ws, "open"); + assert(inspectorUrl, "missing inspectorUrl"); + const ws = new WebSocket(inspectorUrl.href); + const openPromise = events.once(ws, "open"); - const consoleApiMessages: DevToolsEvent<"Runtime.consoleAPICalled">[] = - collectMessagesContaining(ws, "Runtime.consoleAPICalled"); - const executionContextCreatedPromise = waitForMessageContaining( - ws, - "Runtime.executionContextCreated" - ); + const consoleApiMessages: DevToolsEvent<"Runtime.consoleAPICalled">[] = + collectMessagesContaining(ws, "Runtime.consoleAPICalled"); + const executionContextCreatedPromise = waitForMessageContaining( + ws, + "Runtime.executionContextCreated" + ); - await openPromise; - await worker.fetch("http://dummy"); + await openPromise; + await worker.fetch("http://dummy"); - await expect(executionContextCreatedPromise).resolves.toMatchObject({ - method: "Runtime.executionContextCreated", - params: { - context: { id: expect.any(Number) }, - }, - }); - await vi.waitFor( - () => { - expect(consoleApiMessages).toContainMatchingObject({ - method: "Runtime.consoleAPICalled", - params: expect.objectContaining({ - args: [{ type: "string", value: "Inside mock user worker" }], - }), - }); - }, - { timeout: 5_000 } - ); - - // Ensure execution contexts cleared on reload - const executionContextClearedPromise = waitForMessageContaining( - ws, - "Runtime.executionContextsCleared" - ); - await helper.seed({ - "src/index.ts": script.replace("body:1", "body:2"), - }); - await setTimeout(300); + await expect(executionContextCreatedPromise).resolves.toMatchObject({ + method: "Runtime.executionContextCreated", + params: { + context: { id: expect.any(Number) }, + }, + }); + await vi.waitFor( + () => { + expect(consoleApiMessages).toContainMatchingObject({ + method: "Runtime.consoleAPICalled", + params: expect.objectContaining({ + args: [{ type: "string", value: "Inside mock user worker" }], + }), + }); + }, + { timeout: 5_000 } + ); - await executionContextClearedPromise; - }); + // Ensure execution contexts cleared on reload + const executionContextClearedPromise = waitForMessageContaining( + ws, + "Runtime.executionContextsCleared" + ); + await helper.seed({ + "src/index.ts": script.replace("body:1", "body:2"), + }); + await setTimeout(300); - it("InspectorProxyWorker rejects unauthorised requests", async (t) => { - t.onTestFinished(() => worker?.dispose()); + await executionContextClearedPromise; + }); + + it("InspectorProxyWorker rejects unauthorised requests", async (t) => { + t.onTestFinished(() => worker?.dispose()); - await helper.seed({ - "src/index.ts": dedent` + await helper.seed({ + "src/index.ts": dedent` export default { fetch() { return new Response("body:1"); } } `, - }); - - const worker = await startWorker({ - name: "test-worker", - entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), + }); - dev: { remote }, - }); + const worker = await startWorker({ + name: "test-worker", + entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), - const inspectorUrl = await worker.inspectorUrl; - assert(inspectorUrl); + dev: { remote }, + }); - assert(inspectorUrl, "missing inspectorUrl"); - let ws = new WebSocket(inspectorUrl.href, { - setHost: false, - headers: { Host: "example.com" }, - }); + const inspectorUrl = await worker.inspectorUrl; + assert(inspectorUrl); - let openPromise = events.once(ws, "open"); - await expect(openPromise).rejects.toThrow("Unexpected server response"); + assert(inspectorUrl, "missing inspectorUrl"); + let ws = new WebSocket(inspectorUrl.href, { + setHost: false, + headers: { Host: "example.com" }, + }); - // Check validates `Origin` header - assert(inspectorUrl, "missing inspectorUrl"); - ws = new WebSocket(inspectorUrl.href, { origin: "https://example.com" }); - openPromise = events.once(ws, "open"); - await expect(openPromise).rejects.toThrow("Unexpected server response"); - ws.close(); - }); + let openPromise = events.once(ws, "open"); + await expect(openPromise).rejects.toThrow("Unexpected server response"); - // Regression test for https://github.com/cloudflare/workers-sdk/issues/5297 - // The runtime inspector can send messages larger than 1MB limit websocket message permitted by UserWorkers. - // In the real-world, this is encountered when debugging large source files (source maps) - // or inspecting a variable that serializes to a large string. - // Connecting devtools directly to the inspector would work fine, but we proxy the inspector messages - // through a worker (InspectorProxyWorker) which hits the limit (without the fix, compatibilityFlags:["increase_websocket_message_size"]) - // By logging a large string we can verify that the inspector messages are being proxied successfully. - it("InspectorProxyWorker can proxy messages > 1MB", async (t) => { - const consoleInfoSpy = vi - .spyOn(console, "info") - .mockImplementation(() => {}); - const consoleLogSpy = vi.spyOn(console, "log").mockImplementation(() => {}); - - t.onTestFinished(() => { - consoleInfoSpy.mockRestore(); - consoleLogSpy.mockRestore(); - return worker?.dispose(); + // Check validates `Origin` header + assert(inspectorUrl, "missing inspectorUrl"); + ws = new WebSocket(inspectorUrl.href, { origin: "https://example.com" }); + openPromise = events.once(ws, "open"); + await expect(openPromise).rejects.toThrow("Unexpected server response"); + ws.close(); }); - const LARGE_STRING = "This is a large string" + "z".repeat(2 ** 20); + // Regression test for https://github.com/cloudflare/workers-sdk/issues/5297 + // The runtime inspector can send messages larger than 1MB limit websocket message permitted by UserWorkers. + // In the real-world, this is encountered when debugging large source files (source maps) + // or inspecting a variable that serializes to a large string. + // Connecting devtools directly to the inspector would work fine, but we proxy the inspector messages + // through a worker (InspectorProxyWorker) which hits the limit (without the fix, compatibilityFlags:["increase_websocket_message_size"]) + // By logging a large string we can verify that the inspector messages are being proxied successfully. + it("InspectorProxyWorker can proxy messages > 1MB", async (t) => { + const consoleInfoSpy = vi + .spyOn(console, "info") + .mockImplementation(() => {}); + const consoleLogSpy = vi + .spyOn(console, "log") + .mockImplementation(() => {}); + + t.onTestFinished(() => { + consoleInfoSpy.mockRestore(); + consoleLogSpy.mockRestore(); + return worker?.dispose(); + }); - const script = dedent` + const LARGE_STRING = "This is a large string" + "z".repeat(2 ** 20); + + const script = dedent` export default { fetch() { console.log("${LARGE_STRING}"); @@ -233,177 +236,96 @@ describe.each(OPTIONS)("DevEnv (remote: $remote)", ({ remote }) => { } `; - await helper.seed({ - "src/index.ts": script, - }); - - const worker = await startWorker({ - name: "test-worker", - entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), - - dev: { remote }, - }); - - const inspectorUrl = await worker.inspectorUrl; - assert(inspectorUrl, "missing inspectorUrl"); - const ws = new WebSocket(inspectorUrl.href); - - const consoleApiMessages: DevToolsEvent<"Runtime.consoleAPICalled">[] = - collectMessagesContaining(ws, "Runtime.consoleAPICalled"); - - await worker.fetch("http://dummy"); - - await vi.waitFor( - () => { - expect(consoleApiMessages).toContainMatchingObject({ - method: "Runtime.consoleAPICalled", - params: expect.objectContaining({ - args: [{ type: "string", value: LARGE_STRING }], - }), - }); - }, - { timeout: 5_000 } - ); - }); - - // local only: miniflare catches error responses and pretty-prints them - it.skipIf(remote)("User worker exception", async (t) => { - t.onTestFinished(() => worker?.dispose()); - - await helper.seed({ - "src/index.ts": dedent` - export default { - fetch() { - throw new Error('Boom!'); - } - } - `, - }); - - const worker = await startWorker({ - name: "test-worker", - entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), - - dev: { remote }, - }); + await helper.seed({ + "src/index.ts": script, + }); - await expect(worker.fetch("http://dummy")).rejects.toThrowError("Boom!"); + const worker = await startWorker({ + name: "test-worker", + entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), - await helper.seed({ - "src/index.ts": dedent` - export default { - fetch() { - throw new Error('Boom 2!'); - } - } - `, - }); - await setTimeout(300); + dev: { remote }, + }); - await expect(worker.fetch("http://dummy")).rejects.toThrowError("Boom 2!"); + const inspectorUrl = await worker.inspectorUrl; + assert(inspectorUrl, "missing inspectorUrl"); + const ws = new WebSocket(inspectorUrl.href); - // test eyeball requests receive the pretty error page - await helper.seed({ - "src/index.ts": dedent` - export default { - fetch() { - const e = new Error('Boom 3!'); + const consoleApiMessages: DevToolsEvent<"Runtime.consoleAPICalled">[] = + collectMessagesContaining(ws, "Runtime.consoleAPICalled"); - // this is how errors are serialised after they are caught by wrangler/miniflare3 middlewares - const error = { name: e.name, message: e.message, stack: e.stack }; - return Response.json(error, { - status: 500, - headers: { "MF-Experimental-Error-Stack": "true" }, - }); - } - } - `, - }); - await setTimeout(300); + await worker.fetch("http://dummy"); - const undiciRes = await undici.fetch(await worker.url, { - headers: { Accept: "text/html" }, - }); - await expect(undiciRes.text()).resolves.toEqual( - expect.stringContaining(`Boom 3!`) // pretty error page html snippet - ); - - // test further changes that fix the code - await helper.seed({ - "src/index.ts": dedent` - export default { - fetch() { - return new Response("body:3"); - } - } - `, + await vi.waitFor( + () => { + expect(consoleApiMessages).toContainMatchingObject({ + method: "Runtime.consoleAPICalled", + params: expect.objectContaining({ + args: [{ type: "string", value: LARGE_STRING }], + }), + }); + }, + { timeout: 5_000 } + ); }); - await setTimeout(300); - let res = await worker.fetch("http://dummy"); - await expect(res.text()).resolves.toBe("body:3"); - - res = await worker.fetch("http://dummy"); - await expect(res.text()).resolves.toBe("body:3"); - }); - - it("config.dev.{server,inspector} changes, restart the server instance", async (t) => { - t.onTestFinished(() => worker?.dispose()); + it("config.dev.{server,inspector} changes, restart the server instance", async (t) => { + t.onTestFinished(() => worker?.dispose()); - await helper.seed({ - "src/index.ts": dedent` + await helper.seed({ + "src/index.ts": dedent` export default { fetch() { return new Response("body:1"); } } `, - }); + }); - const worker = await startWorker({ - name: "test-worker", - entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), + const worker = await startWorker({ + name: "test-worker", + entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), - dev: { - remote, - server: { port: await getPort() }, - inspector: false, - }, - }); + dev: { + remote, + server: { port: await getPort() }, + inspector: false, + }, + }); - let res = await worker.fetch("http://dummy"); - await expect(res.text()).resolves.toBe("body:1"); + let res = await worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:1"); - const oldPort = worker.config.dev?.server?.port; - let undiciRes = await undici.fetch(`http://127.0.0.1:${oldPort}`); - await expect(undiciRes.text()).resolves.toBe("body:1"); + const oldPort = worker.config.dev?.server?.port; + let undiciRes = await undici.fetch(`http://127.0.0.1:${oldPort}`); + await expect(undiciRes.text()).resolves.toBe("body:1"); - await worker.patchConfig({ - dev: { - ...worker.config.dev, - remote, - server: { port: await getPort() }, - inspector: false, - }, - }); - const newPort = worker.config.dev?.server?.port; + await worker.patchConfig({ + dev: { + ...worker.config.dev, + remote, + server: { port: await getPort() }, + inspector: false, + }, + }); + const newPort = worker.config.dev?.server?.port; - res = await worker.fetch("http://dummy"); - await expect(res.text()).resolves.toBe("body:1"); + res = await worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:1"); - undiciRes = await undici.fetch(`http://127.0.0.1:${newPort}`); - await expect(undiciRes.text()).resolves.toBe("body:1"); + undiciRes = await undici.fetch(`http://127.0.0.1:${newPort}`); + await expect(undiciRes.text()).resolves.toBe("body:1"); - await expect( - undici.fetch(`http://127.0.0.1:${oldPort}`) - ).rejects.toThrowError("fetch failed"); - }); + await expect( + undici.fetch(`http://127.0.0.1:${oldPort}`) + ).rejects.toThrowError("fetch failed"); + }); - it("liveReload", async (t) => { - t.onTestFinished(() => worker?.dispose()); + it("liveReload", async (t) => { + t.onTestFinished(() => worker?.dispose()); - await helper.seed({ - "src/index.ts": dedent` + await helper.seed({ + "src/index.ts": dedent` export default { fetch() { return new Response("body:1", { @@ -412,28 +334,28 @@ describe.each(OPTIONS)("DevEnv (remote: $remote)", ({ remote }) => { } } `, - }); + }); - const worker = await startWorker({ - name: "test-worker", - entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), + const worker = await startWorker({ + name: "test-worker", + entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), - dev: { - remote, - liveReload: true, - }, - }); + dev: { + remote, + liveReload: true, + }, + }); - const scriptRegex = - / `); - await helper.seed({ - "src/index.ts": dedent` + await helper.seed({ + "src/index.ts": dedent` export default { fetch() { return new Response("body:2"); } } `, - }); - await setTimeout(300); + }); + await setTimeout(300); - // test liveReload does nothing when the response Content-Type is not html - res = await worker.fetch("http://dummy"); - resText = await res.text(); - expect(resText).toBe("body:2"); - expect(resText).not.toEqual(expect.stringMatching(scriptRegex)); + // test liveReload does nothing when the response Content-Type is not html + res = await worker.fetch("http://dummy"); + resText = await res.text(); + expect(resText).toBe("body:2"); + expect(resText).not.toEqual(expect.stringMatching(scriptRegex)); - await helper.seed({ - "src/index.ts": dedent` + await helper.seed({ + "src/index.ts": dedent` export default { fetch() { return new Response("body:3", { @@ -481,25 +403,104 @@ describe.each(OPTIONS)("DevEnv (remote: $remote)", ({ remote }) => { } } `, - }); - await worker.patchConfig({ - dev: { - ...worker.config.dev, - liveReload: false, - }, - }); + }); + await worker.patchConfig({ + dev: { + ...worker.config.dev, + liveReload: false, + }, + }); - // test liveReload: false does nothing even when the response Content-Type is html - res = await worker.fetch("http://dummy"); - resText = await res.text(); - expect(resText).toBe("body:3"); - expect(resText).not.toEqual(expect.stringMatching(scriptRegex)); + // test liveReload: false does nothing even when the response Content-Type is html + res = await worker.fetch("http://dummy"); + resText = await res.text(); + expect(resText).toBe("body:3"); + expect(resText).not.toEqual(expect.stringMatching(scriptRegex)); + }); }); - // local only: origin overrides cannot be applied in remote mode - it.skipIf(remote)( - "origin override takes effect in the UserWorker", - async (t) => { + describe("DevEnv (local-only)", () => { + it("User worker exception", async (t) => { + t.onTestFinished(() => worker?.dispose()); + + await helper.seed({ + "src/index.ts": dedent` + export default { + fetch() { + throw new Error('Boom!'); + } + } + `, + }); + + const worker = await startWorker({ + name: "test-worker", + entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), + }); + + await expect(worker.fetch("http://dummy")).rejects.toThrowError("Boom!"); + + await helper.seed({ + "src/index.ts": dedent` + export default { + fetch() { + throw new Error('Boom 2!'); + } + } + `, + }); + await setTimeout(300); + + await expect(worker.fetch("http://dummy")).rejects.toThrowError( + "Boom 2!" + ); + + // test eyeball requests receive the pretty error page + await helper.seed({ + "src/index.ts": dedent` + export default { + fetch() { + const e = new Error('Boom 3!'); + + // this is how errors are serialised after they are caught by wrangler/miniflare3 middlewares + const error = { name: e.name, message: e.message, stack: e.stack }; + return Response.json(error, { + status: 500, + headers: { "MF-Experimental-Error-Stack": "true" }, + }); + } + } + `, + }); + await setTimeout(300); + + const undiciRes = await undici.fetch(await worker.url, { + headers: { Accept: "text/html" }, + }); + await expect(undiciRes.text()).resolves.toEqual( + expect.stringContaining(`Boom 3!`) // pretty error page html snippet + ); + + // test further changes that fix the code + await helper.seed({ + "src/index.ts": dedent` + export default { + fetch() { + return new Response("body:3"); + } + } + `, + }); + await setTimeout(300); + + let res = await worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:3"); + + res = await worker.fetch("http://dummy"); + await expect(res.text()).resolves.toBe("body:3"); + }); + + it("origin override takes effect in the UserWorker", async (t) => { t.onTestFinished(() => worker?.dispose()); await helper.seed({ @@ -517,7 +518,6 @@ describe.each(OPTIONS)("DevEnv (remote: $remote)", ({ remote }) => { entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), dev: { - remote, origin: { hostname: "www.google.com", }, @@ -543,13 +543,9 @@ describe.each(OPTIONS)("DevEnv (remote: $remote)", ({ remote }) => { await expect(res.text()).resolves.toBe( "URL: https://mybank.co.uk/test/path/2" ); - } - ); + }); - // local only: remote workers are not terminated during reloads - it.skipIf(remote)( - "inflight requests are retried during UserWorker reloads", - async (t) => { + it("inflight requests are retried during UserWorker reloads", async (t) => { // to simulate inflight requests failing during UserWorker reloads, // we will use a UserWorker with a longish `await setTimeout(...)` // so that we can guarantee the race condition is hit when workerd is eventually terminated @@ -578,8 +574,6 @@ describe.each(OPTIONS)("DevEnv (remote: $remote)", ({ remote }) => { const worker = await startWorker({ name: "test-worker", entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), - - dev: { remote }, }); let res = await worker.fetch("http://dummy/short"); @@ -605,6 +599,162 @@ describe.each(OPTIONS)("DevEnv (remote: $remote)", ({ remote }) => { res = await inflightDuringReloads; await expect(res.text()).resolves.toBe("UserWorker:3"); - } - ); + }); + + it("vars from .env (next to config file) override vars from Wrangler config file", async (t) => { + t.onTestFinished(() => worker?.dispose()); + await helper.seed({ + "src/index.ts": dedent` + export default { + fetch(request, env) { + return Response.json(env); + } + } + `, + "wrangler.jsonc": JSON.stringify({ + vars: { + WRANGLER_ENV_VAR_0: "default-0", + WRANGLER_ENV_VAR_1: "default-1", + WRANGLER_ENV_VAR_2: "default-2", + WRANGLER_ENV_VAR_3: "default-3", + }, + }), + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + ".env.local": dedent` + WRANGLER_ENV_VAR_2=local-2 + WRANGLER_ENV_VAR_3=local-3 + `, + ".env.staging": dedent` + WRANGLER_ENV_VAR_3=staging-3 + WRANGLER_ENV_VAR_4=staging-4 + `, + ".env.staging.local": dedent` + WRANGLER_ENV_VAR_4=staging-local-4 + WRANGLER_ENV_VAR_5=staging-local-5 + `, + }); + + const worker = await startWorker({ + config: path.resolve(helper.tmpPath, "wrangler.jsonc"), + name: "test-worker", + entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), + }); + + const res = await worker.fetch("http://dummy/test/path/1"); + expect(await res.json()).toMatchInlineSnapshot(` + { + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "env-1", + "WRANGLER_ENV_VAR_2": "local-2", + "WRANGLER_ENV_VAR_3": "local-3", + } + `); + }); + + it("vars are not loaded from .env if there is a .dev.vars file (next to config file)", async (t) => { + t.onTestFinished(() => worker?.dispose()); + await helper.seed({ + "src/index.ts": dedent` + export default { + fetch(request, env) { + return Response.json(env); + } + } + `, + "wrangler.jsonc": JSON.stringify({ + vars: { + WRANGLER_ENV_VAR_0: "default-0", + WRANGLER_ENV_VAR_1: "default-1", + WRANGLER_ENV_VAR_2: "default-2", + WRANGLER_ENV_VAR_3: "default-3", + }, + }), + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + ".dev.vars": dedent` + WRANGLER_ENV_VAR_2=dev-vars-2 + WRANGLER_ENV_VAR_3=dev-vars-3 + `, + }); + + const worker = await startWorker({ + config: path.resolve(helper.tmpPath, "wrangler.jsonc"), + name: "test-worker", + entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), + }); + + const res = await worker.fetch("http://dummy/test/path/1"); + expect(await res.json()).toMatchInlineSnapshot(` + { + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "default-1", + "WRANGLER_ENV_VAR_2": "dev-vars-2", + "WRANGLER_ENV_VAR_3": "dev-vars-3", + } + `); + }); + + it("vars from inline config override vars from both .env and config file", async (t) => { + t.onTestFinished(() => worker?.dispose()); + await helper.seed({ + "src/index.ts": dedent` + export default { + fetch(request, env) { + return Response.json(env); + } + } + `, + "wrangler.jsonc": JSON.stringify({ + vars: { + WRANGLER_ENV_VAR_0: "default-0", + WRANGLER_ENV_VAR_1: "default-1", + WRANGLER_ENV_VAR_2: "default-2", + WRANGLER_ENV_VAR_3: "default-3", + }, + }), + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + ".env.local": dedent` + WRANGLER_ENV_VAR_2=local-2 + WRANGLER_ENV_VAR_3=local-3 + `, + ".env.staging": dedent` + WRANGLER_ENV_VAR_3=staging-3 + WRANGLER_ENV_VAR_4=staging-4 + `, + ".env.staging.local": dedent` + WRANGLER_ENV_VAR_4=staging-local-4 + WRANGLER_ENV_VAR_5=staging-local-5 + `, + }); + + const worker = await startWorker({ + config: path.resolve(helper.tmpPath, "wrangler.jsonc"), + name: "test-worker", + entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), + bindings: { + WRANGLER_ENV_VAR_3: { type: "plain_text", value: "inline-3" }, + WRANGLER_ENV_VAR_4: { type: "plain_text", value: "inline-4" }, + }, + }); + + const res = await worker.fetch("http://dummy/test/path/1"); + expect(await res.json()).toMatchInlineSnapshot(` + { + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "env-1", + "WRANGLER_ENV_VAR_2": "local-2", + "WRANGLER_ENV_VAR_3": "inline-3", + "WRANGLER_ENV_VAR_4": "inline-4", + } + `); + }); + }); }); diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index ee0792f6d027..be424d0948b1 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -116,6 +116,7 @@ "date-fns": "^4.1.0", "devtools-protocol": "^0.0.1182435", "dotenv": "^16.3.1", + "dotenv-expand": "^12.0.2", "execa": "^6.1.0", "find-up": "^6.3.0", "get-port": "^7.0.0", diff --git a/packages/wrangler/src/__tests__/dev.test.ts b/packages/wrangler/src/__tests__/dev.test.ts index 373d4eae9ad9..5ab4d2453e50 100644 --- a/packages/wrangler/src/__tests__/dev.test.ts +++ b/packages/wrangler/src/__tests__/dev.test.ts @@ -958,44 +958,107 @@ describe.sequential("wrangler dev", () => { afterEach(() => (process.env = processEnv)); beforeEach(() => { - fs.writeFileSync(".env", "CUSTOM_BUILD_VAR=default"); - fs.writeFileSync(".env.custom", "CUSTOM_BUILD_VAR=custom"); + fs.writeFileSync( + ".env", + dedent` + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_1=default-1 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_2=default-2 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=default-3 + ` + ); + fs.writeFileSync( + ".env.local", + dedent` + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_1=default-local-1 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_LOCAL=default-local + ` + ); + fs.writeFileSync( + ".env.custom", + dedent` + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_2=custom-2 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=custom-3 + ` + ); + fs.writeFileSync( + ".env.custom.local", + dedent` + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_1=custom-local-1 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=custom-local-3 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_LOCAL=custom-local + ` + ); + fs.writeFileSync( + "build.js", + dedent` + const customFields = Object.entries(process.env).filter(([key]) => key.startsWith('__DOT_ENV_TEST_CUSTOM_BUILD_VAR')); + console.log(customFields.map(([key, value]) => key + "=" + value).join('\\n')); + ` + ); fs.writeFileSync("index.js", `export default {};`); writeWranglerConfig({ main: "index.js", - env: { custom: {} }, - build: { - // Ideally, we'd just log the var here and match it in `std.out`, - // but stdout from custom builds is piped directly to - // `process.stdout` which we don't capture. - command: `node -e "require('fs').writeFileSync('var.txt', process.env.CUSTOM_BUILD_VAR)"`, - }, + env: { custom: {}, noEnv: {} }, + build: { command: `node ./build.js` }, }); - - // We won't overwrite existing process.env keys with .env values (to - // allow .env overrides to be specified on the shell), so make sure this - // key definitely doesn't exist. - vi.stubEnv("CUSTOM_BUILD_VAR", ""); - delete process.env.CUSTOM_BUILD_VAR; }); - it("should load environment variables from `.env`", async () => { + function extractCustomBuildLogs(stdout: string) { + return stdout + .split("\n") + .filter((line) => line.startsWith("[custom build]")) + .map((line) => line.replace(/\[custom build\]( |$)/, "")) + .sort() + .join("\n"); + } + + it("should pass environment variables from `.env` to custom builds", async () => { await runWranglerUntilConfig("dev"); - const output = fs.readFileSync("var.txt", "utf8"); - expect(output).toMatch("default"); + expect(extractCustomBuildLogs(std.out)).toMatchInlineSnapshot(` + " + Running: node ./build.js + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_1=default-local-1 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_2=default-2 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=default-3 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_LOCAL=default-local" + `); }); + it("should prefer to load environment variables from `.env.` if `--env ` is set", async () => { await runWranglerUntilConfig("dev --env custom"); - const output = fs.readFileSync("var.txt", "utf8"); - expect(output).toMatch("custom"); + expect(extractCustomBuildLogs(std.out)).toMatchInlineSnapshot(` + " + Running: node ./build.js + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_1=custom-local-1 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_2=custom-2 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=custom-local-3 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_LOCAL=custom-local" + `); }); - it("should show reasonable debug output if `.env` does not exist", async () => { - fs.rmSync(".env"); - writeWranglerConfig({ - main: "index.js", - }); - await runWranglerUntilConfig("dev --log-level debug"); - expect(std.debug).toContain(".env file not found at"); + + it("should use default `.env` if `.env.` does not exist", async () => { + await runWranglerUntilConfig("dev --env=noEnv"); + expect(extractCustomBuildLogs(std.out)).toMatchInlineSnapshot(` + " + Running: node ./build.js + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_1=default-local-1 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_2=default-2 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=default-3 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_LOCAL=default-local" + `); + }); + + it("should not override environment variables already on process.env", async () => { + vi.stubEnv("__DOT_ENV_TEST_CUSTOM_BUILD_VAR_1", "process-env"); + await runWranglerUntilConfig("dev"); + expect(extractCustomBuildLogs(std.out)).toMatchInlineSnapshot(` + " + Running: node ./build.js + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_1=process-env + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_2=default-2 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=default-3 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_LOCAL=default-local" + `); }); }); }); @@ -1470,6 +1533,127 @@ describe.sequential("wrangler dev", () => { }); }); + describe(".env in local dev", () => { + const processEnv = process.env; + beforeEach(() => (process.env = { ...processEnv })); + afterEach(() => (process.env = processEnv)); + + beforeEach(() => { + fs.writeFileSync( + ".env", + dedent` + __DOT_ENV_LOCAL_DEV_VAR_1=default-1 + __DOT_ENV_LOCAL_DEV_VAR_2=default-2 + __DOT_ENV_LOCAL_DEV_VAR_3=default-3 + ` + ); + fs.writeFileSync( + ".env.local", + dedent` + __DOT_ENV_LOCAL_DEV_VAR_1=default-local-1 + __DOT_ENV_LOCAL_DEV_VAR_LOCAL=default-local + ` + ); + fs.writeFileSync( + ".env.custom", + dedent` + __DOT_ENV_LOCAL_DEV_VAR_2=custom-2 + __DOT_ENV_LOCAL_DEV_VAR_3=custom-3 + ` + ); + fs.writeFileSync( + ".env.custom.local", + dedent` + __DOT_ENV_LOCAL_DEV_VAR_1=custom-local-1 + __DOT_ENV_LOCAL_DEV_VAR_3=custom-local-3 + __DOT_ENV_LOCAL_DEV_VAR_LOCAL=custom-local + ` + ); + fs.writeFileSync("index.js", `export default {};`); + writeWranglerConfig({ + main: "index.js", + }); + }); + + function extractUsingVars(stdout: string) { + return stdout + .split("\n") + .filter((line) => line.startsWith("Using vars")) + .sort() + .join("\n"); + } + + function extractBindings(stdout: string) { + return stdout + .split("\n") + .filter((line) => line.startsWith("env.")) + .sort() + .join("\n"); + } + + it("should get local dev `vars` from `.env`", async () => { + await runWranglerUntilConfig("dev"); + expect(extractUsingVars(std.out)).toMatchInlineSnapshot(` + "Using vars defined in .env + Using vars defined in .env.local" + `); + expect(extractBindings(std.out)).toMatchInlineSnapshot(` + "env.__DOT_ENV_LOCAL_DEV_VAR_1 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_2 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_3 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_LOCAL (\\"(hidden)\\") Environment Variable local" + `); + }); + + it("should get local dev `vars` from appropriate `.env.` files when --env= is set", async () => { + await runWranglerUntilConfig("dev --env custom"); + expect(extractUsingVars(std.out)).toMatchInlineSnapshot(` + "Using vars defined in .env + Using vars defined in .env.custom + Using vars defined in .env.custom.local + Using vars defined in .env.local" + `); + expect(extractBindings(std.out)).toMatchInlineSnapshot(` + "env.__DOT_ENV_LOCAL_DEV_VAR_1 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_2 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_3 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_LOCAL (\\"(hidden)\\") Environment Variable local" + `); + }); + + it("should get local dev vars from appropriate `.env` files when --env= is set but no .env. file exists", async () => { + await runWranglerUntilConfig("dev --env noEnv"); + expect(extractUsingVars(std.out)).toMatchInlineSnapshot(` + "Using vars defined in .env + Using vars defined in .env.local" + `); + expect(extractBindings(std.out)).toMatchInlineSnapshot(` + "env.__DOT_ENV_LOCAL_DEV_VAR_1 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_2 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_3 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_LOCAL (\\"(hidden)\\") Environment Variable local" + `); + }); + + it("should get local dev `vars` from `process.env` when `CLOUDFLARE_INCLUDE_PROCESS_ENV` is true", async () => { + await runWranglerUntilConfig("dev --env custom", { + CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", + }); + expect(extractUsingVars(std.out)).toMatchInlineSnapshot(` + "Using vars defined in .env + Using vars defined in .env.custom + Using vars defined in .env.custom.local + Using vars defined in .env.local + Using vars defined in process.env" + `); + // We could dump out all the bindings but that would be a lot of noise, and also may change between OSes and runs. + // Instead, we know that the `CLOUDFLARE_INCLUDE_PROCESS_ENV` variable should be present, so we just check for that. + expect(extractBindings(std.out)).contains( + 'env.CLOUDFLARE_INCLUDE_PROCESS_ENV ("(hidden)")' + ); + }); + }); + describe("serve static assets", () => { it("should error if --site is used with no value", async () => { await expect( diff --git a/packages/wrangler/src/__tests__/type-generation.test.ts b/packages/wrangler/src/__tests__/type-generation.test.ts index c8bddbd8ae57..be9d000ce309 100644 --- a/packages/wrangler/src/__tests__/type-generation.test.ts +++ b/packages/wrangler/src/__tests__/type-generation.test.ts @@ -1046,6 +1046,16 @@ describe("generate types", () => { `; fs.writeFileSync(".dev.vars", localVarsEnvContent, "utf8"); + // Add a .env file that will be ignored due to there being a .dev.vars file + const dotEnvContent = dedent` + # Preceding comment + SECRET_A="A from .dev.vars" + MULTI_LINE_SECRET="A: line 1 + line 2" + UNQUOTED_SECRET= unquoted value + `; + fs.writeFileSync(".env", dotEnvContent, "utf8"); + await runWrangler("types --include-runtime=false"); expect(std.out).toMatchInlineSnapshot(` @@ -1070,6 +1080,51 @@ describe("generate types", () => { `); }); + it("should include secret keys from .env, if there is no .dev.vars", async () => { + fs.writeFileSync( + "./wrangler.jsonc", + JSON.stringify({ + vars: { + myTomlVarA: "A from wrangler toml", + myTomlVarB: "B from wrangler toml", + }, + }), + "utf-8" + ); + + const dotEnvContent = dedent` + # Preceding comment + SECRET_A_DOT_ENV="A from .env" + MULTI_LINE_SECRET="A: line 1 + line 2" + UNQUOTED_SECRET= unquoted value + `; + fs.writeFileSync(".env", dotEnvContent, "utf8"); + + await runWrangler("types --include-runtime=false"); + + expect(std.out).toMatchInlineSnapshot(` + "Generating project types... + + declare namespace Cloudflare { + interface Env { + myTomlVarA: \\"A from wrangler toml\\"; + myTomlVarB: \\"B from wrangler toml\\"; + SECRET_A_DOT_ENV: string; + MULTI_LINE_SECRET: string; + UNQUOTED_SECRET: string; + } + } + interface Env extends Cloudflare.Env {} + + ──────────────────────────────────────────────────────────── + ✨ Types written to worker-configuration.d.ts + + 📣 Remember to rerun 'wrangler types' after you change your wrangler.json file. + " + `); + }); + it("should allow opting out of strict-vars", async () => { fs.writeFileSync( "./wrangler.jsonc", diff --git a/packages/wrangler/src/config/dot-env.ts b/packages/wrangler/src/config/dot-env.ts new file mode 100644 index 000000000000..47b479a2ace4 --- /dev/null +++ b/packages/wrangler/src/config/dot-env.ts @@ -0,0 +1,71 @@ +import path from "path"; +import dotenv from "dotenv"; +import dotenvExpand from "dotenv-expand"; +import { logger } from "../logger"; + +/** + * Generates the default set of paths for .env file loading. + * + * The default order is `.env`, `.env.local`, `.env.`, and `.env..local` in that order. + */ +export function getDefaultEnvPaths( + basePath: string, + env: string | undefined +): string[] { + // Generate the default paths for .env files based on the provided base path and environment. + const envPaths = [basePath, basePath + ".local"]; + if (env !== undefined) { + envPaths.push(`${basePath}.${env}`); + envPaths.push(`${basePath}.${env}.local`); + } + return envPaths; +} + +/** + * Loads environment variables from .env files. + * + * This will merge values from each of of the `envPaths` in order. + * Values in the file at `envPaths[x+1]` will override the values in the files at `envPaths[x]`. + * + * Further, once merged values are expanded, meaning that if a value references another variable + * (e.g., `FOO=${BAR}`), it will be replaced with the value of `BAR` if it exists. + */ +export function loadDotEnv( + envPaths: string[], + { includeProcessEnv, silent }: { includeProcessEnv: boolean; silent: boolean } +): dotenv.DotenvParseOutput | undefined { + // The `parsedEnv` object will be mutated to contain the merged values. + const parsedEnv = {}; + for (const envPath of envPaths) { + // The `parsed` object only contains the values from the loaded .env file. + const { error, parsed } = dotenv.config({ + path: envPath, + processEnv: parsedEnv, + override: true, + }); + if (error) { + logger.debug(`Failed to load .env file "${envPath}":`, error); + } else if (parsed && !silent) { + const relativePath = path.relative(process.cwd(), envPath); + logger.log(`Using vars defined in ${relativePath}`); + } + } + + // The `expandedEnv` object will be mutated to include the expanded values from `parsedEnv` + // but only if the key is not already defined in `expandedEnv`. + const expandedEnv = {}; + if (includeProcessEnv) { + Object.assign(expandedEnv, process.env); + if (!silent) { + logger.log("Using vars defined in process.env"); + } + } + const { error } = dotenvExpand.expand({ + processEnv: expandedEnv, + parsed: parsedEnv, + }); + if (error) { + logger.debug(`Failed to expand .env values:`, error); + } + return expandedEnv; +} diff --git a/packages/wrangler/src/config/index.ts b/packages/wrangler/src/config/index.ts index b70115592252..fb0361e39a1e 100644 --- a/packages/wrangler/src/config/index.ts +++ b/packages/wrangler/src/config/index.ts @@ -1,7 +1,4 @@ -import path from "node:path"; -import { maybeGetFile } from "@cloudflare/workers-shared"; import TOML from "@iarna/toml"; -import dotenv from "dotenv"; import { FatalError, UserError } from "../errors"; import { logger } from "../logger"; import { EXIT_CODE_INVALID_PAGES_CONFIG } from "../pages/errors"; @@ -211,44 +208,3 @@ export function withConfig( return handler({ ...args, config: readConfig(args, options) }); }; } - -export interface DotEnv { - path: string; - parsed: dotenv.DotenvParseOutput; -} - -function tryLoadDotEnv(basePath: string): DotEnv | undefined { - try { - const contents = maybeGetFile(basePath); - if (contents === undefined) { - logger.debug( - `.env file not found at "${path.relative(".", basePath)}". Continuing... For more details, refer to https://developers.cloudflare.com/workers/wrangler/system-environment-variables/` - ); - return; - } - - const parsed = dotenv.parse(contents); - return { path: basePath, parsed }; - } catch (e) { - logger.debug( - `Failed to load .env file "${path.relative(".", basePath)}":`, - e - ); - } -} - -/** - * Loads a dotenv file from `envPath`, preferring to read `${envPath}.${env}` if - * `env` is defined and that file exists. - * - * Note: The `getDotDevDotVarsContent` function in the `packages/vite-plugin-cloudflare/src/dev-vars.ts` file - * follows the same logic implemented here, the two need to be kept in sync, so if you modify some logic - * here make sure that, if applicable, the same change is reflected there - */ -export function loadDotEnv(envPath: string, env?: string): DotEnv | undefined { - if (env === undefined) { - return tryLoadDotEnv(envPath); - } else { - return tryLoadDotEnv(`${envPath}.${env}`) ?? tryLoadDotEnv(envPath); - } -} diff --git a/packages/wrangler/src/dev/dev-vars.ts b/packages/wrangler/src/dev/dev-vars.ts index 9d889dfd2598..e326ce9c0b84 100644 --- a/packages/wrangler/src/dev/dev-vars.ts +++ b/packages/wrangler/src/dev/dev-vars.ts @@ -1,5 +1,8 @@ import * as path from "node:path"; -import { loadDotEnv } from "../config"; +import { maybeGetFile } from "@cloudflare/workers-shared"; +import dotenv from "dotenv"; +import { getDefaultEnvPaths, loadDotEnv } from "../config/dot-env"; +import { getCloudflareIncludeProcessEnvFromEnv } from "../environment-variables/misc-variables"; import { logger } from "../logger"; import type { Config } from "../config"; @@ -16,8 +19,12 @@ import type { Config } from "../config"; * Wrangler configuration). If the `--env ` option is set, we'll first look for * `.dev.vars.`. * - * Any values in this file, formatted like a `dotenv` file, will add to or override `vars` + * If there are no `.dev.vars*` file, we will look for `.env*` files in the same directory. + * If the `--env-file ` option is set, we'll look for the `.env*` files at that path. + * + * Any values in these files (all formatted like `.env` files) will add to or override `vars` * bindings provided in the Wrangler configuration file. + * */ export function getVarsForDev( config: Pick, @@ -27,8 +34,10 @@ export function getVarsForDev( const configDir = path.resolve( config.userConfigPath ? path.dirname(config.userConfigPath) : "." ); + + // First, try to load from .dev.vars const devVarsPath = path.resolve(configDir, ".dev.vars"); - const loaded = loadDotEnv(devVarsPath, env); + const loaded = loadDotDevDotVars(devVarsPath, env); if (loaded !== undefined) { const devVarsRelativePath = path.relative(process.cwd(), loaded.path); if (!silent) { @@ -39,6 +48,59 @@ export function getVarsForDev( ...loaded.parsed, }; } else { - return config.vars; + // If no .dev.vars files load vars from .env files in the configuration directory. + const dotEnvVars = loadDotEnv( + getDefaultEnvPaths(path.resolve(path.join(configDir, ".env")), env), + { + includeProcessEnv: getCloudflareIncludeProcessEnvFromEnv(), + silent, + } + ); + return { + ...config.vars, + ...dotEnvVars, + }; + } +} + +export interface DotDevDotVars { + path: string; + parsed: dotenv.DotenvParseOutput; +} + +function tryLoadDotDevDotVars(basePath: string): DotDevDotVars | undefined { + try { + const contents = maybeGetFile(basePath); + if (contents === undefined) { + logger.debug( + `local dev variables file not found at "${path.relative(".", basePath)}". Continuing... For more details, refer to https://developers.cloudflare.com/workers/wrangler/system-environment-variables/` + ); + return; + } + + const parsed = dotenv.parse(contents); + return { path: basePath, parsed }; + } catch (e) { + logger.debug( + `Failed to load local dev variables file "${path.relative(".", basePath)}":`, + e + ); + } +} + +/** + * Loads a .dev.vars (or .env style) file from `envPath`, preferring to read `${envPath}.${env}` if + * `env` is defined and that file exists. + */ +export function loadDotDevDotVars( + envPath: string, + env?: string +): DotDevDotVars | undefined { + if (env === undefined) { + return tryLoadDotDevDotVars(envPath); + } else { + return ( + tryLoadDotDevDotVars(`${envPath}.${env}`) ?? tryLoadDotDevDotVars(envPath) + ); } } diff --git a/packages/wrangler/src/environment-variables/factory.ts b/packages/wrangler/src/environment-variables/factory.ts index 2076b7fd1f25..741bc6c88738 100644 --- a/packages/wrangler/src/environment-variables/factory.ts +++ b/packages/wrangler/src/environment-variables/factory.ts @@ -38,7 +38,8 @@ type VariableNames = // We don't get the following using the environment variable factory, // but including here so that all environment variables are documented here: | "WRANGLER_DOCKER_HOST" - | "DOCKER_HOST"; + | "DOCKER_HOST" + | "CLOUDFLARE_INCLUDE_PROCESS_ENV"; type DeprecatedNames = | "CF_ACCOUNT_ID" diff --git a/packages/wrangler/src/environment-variables/misc-variables.ts b/packages/wrangler/src/environment-variables/misc-variables.ts index c6f80ce6ef5a..a50cb03dc0e8 100644 --- a/packages/wrangler/src/environment-variables/misc-variables.ts +++ b/packages/wrangler/src/environment-variables/misc-variables.ts @@ -273,3 +273,12 @@ export const getDockerPath = getEnvironmentVariableFactory({ return "docker"; }, }); + +/** + * `CLOUDFLARE_INCLUDE_PROCESS_ENV` specifies whether to include the `process.env` in vars loaded from `.env` for local development. + */ +export const getCloudflareIncludeProcessEnvFromEnv = + getBooleanEnvironmentVariableFactory({ + variableName: "CLOUDFLARE_INCLUDE_PROCESS_ENV", + defaultValue: () => false, + }); diff --git a/packages/wrangler/src/index.ts b/packages/wrangler/src/index.ts index a83aab8bb977..49abd521ccf3 100644 --- a/packages/wrangler/src/index.ts +++ b/packages/wrangler/src/index.ts @@ -1,5 +1,6 @@ import assert from "node:assert"; import os from "node:os"; +import { resolve } from "node:path"; import { setTimeout } from "node:timers/promises"; import { ApiError } from "@cloudflare/containers-shared"; import chalk from "chalk"; @@ -21,7 +22,8 @@ import { } from "./cert/cert"; import { checkNamespace, checkStartupCommand } from "./check/commands"; import { cloudchamber } from "./cloudchamber"; -import { experimental_readRawConfig, loadDotEnv, readConfig } from "./config"; +import { experimental_readRawConfig, readConfig } from "./config"; +import { getDefaultEnvPaths, loadDotEnv } from "./config/dot-env"; import { containers } from "./containers"; import { demandSingleValue } from "./core"; import { CommandRegistry } from "./core/CommandRegistry"; @@ -420,12 +422,11 @@ export function createCLIParser(argv: string[]) { }) .check((args) => { // Grab locally specified env params from `.env` file - const loaded = loadDotEnv(".env", args.env); - for (const [key, value] of Object.entries(loaded?.parsed ?? {})) { - if (!(key in process.env)) { - process.env[key] = value; - } - } + process.env = + loadDotEnv(getDefaultEnvPaths(resolve(".env"), args.env), { + includeProcessEnv: true, + silent: true, + }) ?? process.env; // Write a session entry to the output file (if there is one). writeOutput({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1698d64190e7..1e3707aec20a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3508,6 +3508,9 @@ importers: dotenv: specifier: ^16.3.1 version: 16.3.1 + dotenv-expand: + specifier: ^12.0.2 + version: 12.0.2 execa: specifier: ^6.1.0 version: 6.1.0 @@ -8558,6 +8561,10 @@ packages: resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} engines: {node: '>=12'} + dotenv-expand@12.0.2: + resolution: {integrity: sha512-lXpXz2ZE1cea1gL4sz2Ipj8y4PiVjytYr3Ij0SWoms1PGxIv7m2CRKuRuCRtHdVuvM/hNJPMxt5PbhboNC4dPQ==} + engines: {node: '>=12'} + dotenv@16.0.3: resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} engines: {node: '>=12'} @@ -8566,6 +8573,10 @@ packages: resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} engines: {node: '>=12'} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + dotenv@8.6.0: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} @@ -18633,10 +18644,16 @@ snapshots: dotenv-expand@10.0.0: {} + dotenv-expand@12.0.2: + dependencies: + dotenv: 16.6.1 + dotenv@16.0.3: {} dotenv@16.3.1: {} + dotenv@16.6.1: {} + dotenv@8.6.0: {} downshift@6.1.12(react@18.3.1): From b659ce8716b77da9f941359d21ed0643a4cf3089 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 11 Jul 2025 08:55:32 +0100 Subject: [PATCH 02/42] add support to Wrangler for setting the path to the .env files - a global `--env-file` option for Wrangler commands - an option `envFile` for Wrangler API calls --- packages/wrangler/e2e/dev.test.ts | 42 +++ packages/wrangler/e2e/startWorker.test.ts | 56 ++++ packages/wrangler/src/__tests__/ai.test.ts | 22 +- packages/wrangler/src/__tests__/cert.test.ts | 11 +- .../src/__tests__/cloudchamber/create.test.ts | 11 +- .../src/__tests__/cloudchamber/curl.test.ts | 11 +- .../src/__tests__/cloudchamber/delete.test.ts | 11 +- .../src/__tests__/cloudchamber/images.test.ts | 22 +- .../src/__tests__/cloudchamber/list.test.ts | 11 +- .../src/__tests__/cloudchamber/modify.test.ts | 11 +- .../src/__tests__/containers/delete.test.ts | 11 +- .../src/__tests__/containers/info.test.ts | 11 +- .../src/__tests__/containers/list.test.ts | 11 +- packages/wrangler/src/__tests__/d1/d1.test.ts | 44 ++-- .../src/__tests__/deployments.test.ts | 11 +- packages/wrangler/src/__tests__/dev.test.ts | 121 +++++++++ packages/wrangler/src/__tests__/docs.test.ts | 11 +- .../wrangler/src/__tests__/hyperdrive.test.ts | 22 +- packages/wrangler/src/__tests__/index.test.ts | 77 +++--- packages/wrangler/src/__tests__/kv.test.ts | 165 ++++++------ .../src/__tests__/mtls-certificates.test.ts | 11 +- .../src/__tests__/pages/deploy.test.ts | 7 +- .../src/__tests__/pages/pages.test.ts | 49 ++-- .../wrangler/src/__tests__/pipelines.test.ts | 22 +- .../wrangler/src/__tests__/pubsub.test.ts | 33 +-- .../wrangler/src/__tests__/queues.test.ts | 165 ++++++------ packages/wrangler/src/__tests__/r2.test.ts | 242 ++++++++++-------- .../src/__tests__/secrets-store.test.ts | 54 ++-- .../src/__tests__/vectorize/vectorize.test.ts | 44 ++-- .../__tests__/versions/versions.help.test.ts | 22 +- .../src/__tests__/worker-namespace.test.ts | 55 ++-- .../wrangler/src/__tests__/workflows.test.ts | 22 +- packages/wrangler/src/api/dev.ts | 2 + .../src/api/integrations/platform/index.ts | 15 +- .../api/startDevWorker/ConfigController.ts | 2 + .../wrangler/src/api/startDevWorker/types.ts | 6 + packages/wrangler/src/dev.ts | 9 +- packages/wrangler/src/dev/dev-vars.ts | 28 +- packages/wrangler/src/index.ts | 22 +- packages/wrangler/src/pages/dev.ts | 1 + .../wrangler/src/type-generation/index.ts | 4 +- packages/wrangler/src/yargs-types.ts | 1 + 42 files changed, 940 insertions(+), 568 deletions(-) diff --git a/packages/wrangler/e2e/dev.test.ts b/packages/wrangler/e2e/dev.test.ts index eb4e33df710e..43596bc96f0e 100644 --- a/packages/wrangler/e2e/dev.test.ts +++ b/packages/wrangler/e2e/dev.test.ts @@ -2541,4 +2541,46 @@ describe(".env support in local dev", () => { '"WRANGLER_ENV_VAR_1": "env-1"' ); }); + + it("should load environment variables from the .env files pointed to by `--env-file`", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed(seedFiles); + await helper.seed({ + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + }); + await helper.seed({ + ".env.local": dedent` + WRANGLER_ENV_VAR_2=local-2 + WRANGLER_ENV_VAR_3=local-3 + `, + }); + await helper.seed({ + "other/.env": dedent` + WRANGLER_ENV_VAR_1=other-env-1 + WRANGLER_ENV_VAR_2=other-env-2 + `, + }); + await helper.seed({ + "other/.env.local": dedent` + WRANGLER_ENV_VAR_2=other-local-2 + WRANGLER_ENV_VAR_3=other-local-3 + `, + }); + + const worker = helper.runLongLived( + "wrangler dev --env-file=other/.env --env-file=other/.env.local" + ); + const { url } = await worker.waitForReady(); + expect(await (await fetch(url)).text()).toMatchInlineSnapshot(` + "{ + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "other-env-1", + "WRANGLER_ENV_VAR_2": "other-local-2", + "WRANGLER_ENV_VAR_3": "other-local-3", + }" + `); + }); }); diff --git a/packages/wrangler/e2e/startWorker.test.ts b/packages/wrangler/e2e/startWorker.test.ts index 3fdd2adb42be..ca341cfeed0b 100644 --- a/packages/wrangler/e2e/startWorker.test.ts +++ b/packages/wrangler/e2e/startWorker.test.ts @@ -756,5 +756,61 @@ describe("DevEnv", () => { } `); }); + + it("vars from .env pointed at by `envFile` override vars from Wrangler config file and .env files local to the config file", async (t) => { + t.onTestFinished(() => worker?.dispose()); + await helper.seed({ + "src/index.ts": dedent` + export default { + fetch(request, env) { + return Response.json(env); + } + } + `, + "wrangler.jsonc": JSON.stringify({ + vars: { + WRANGLER_ENV_VAR_0: "default-0", + WRANGLER_ENV_VAR_1: "default-1", + WRANGLER_ENV_VAR_2: "default-2", + WRANGLER_ENV_VAR_3: "default-3", + }, + }), + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + ".env.local": dedent` + WRANGLER_ENV_VAR_2=local-2 + WRANGLER_ENV_VAR_3=local-3 + `, + "other/.env": dedent` + WRANGLER_ENV_VAR_3=other-3 + WRANGLER_ENV_VAR_4=other-4 + `, + "other/.env.local": dedent` + WRANGLER_ENV_VAR_4=other-local-4 + WRANGLER_ENV_VAR_5=other-local-5 + `, + }); + + const worker = await startWorker({ + config: path.resolve(helper.tmpPath, "wrangler.jsonc"), + name: "test-worker", + entrypoint: path.resolve(helper.tmpPath, "src/index.ts"), + envFiles: ["other/.env", "other/.env.local"], + }); + + const res = await worker.fetch("http://dummy/test/path/1"); + expect(await res.json()).toMatchInlineSnapshot(` + { + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "default-1", + "WRANGLER_ENV_VAR_2": "default-2", + "WRANGLER_ENV_VAR_3": "other-3", + "WRANGLER_ENV_VAR_4": "other-local-4", + "WRANGLER_ENV_VAR_5": "other-local-5", + } + `); + }); }); }); diff --git a/packages/wrangler/src/__tests__/ai.test.ts b/packages/wrangler/src/__tests__/ai.test.ts index b082a23af7ae..d04e4f58ae81 100644 --- a/packages/wrangler/src/__tests__/ai.test.ts +++ b/packages/wrangler/src/__tests__/ai.test.ts @@ -26,11 +26,12 @@ describe("ai help", () => { wrangler ai finetune Interact with finetune files GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -55,11 +56,12 @@ describe("ai help", () => { wrangler ai finetune Interact with finetune files GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); }); diff --git a/packages/wrangler/src/__tests__/cert.test.ts b/packages/wrangler/src/__tests__/cert.test.ts index ee54cba2795f..2bdf72b20447 100644 --- a/packages/wrangler/src/__tests__/cert.test.ts +++ b/packages/wrangler/src/__tests__/cert.test.ts @@ -484,11 +484,12 @@ describe("wrangler", () => { wrangler cert delete Delete an mTLS certificate GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); }); diff --git a/packages/wrangler/src/__tests__/cloudchamber/create.test.ts b/packages/wrangler/src/__tests__/cloudchamber/create.test.ts index 7ff776c5cd60..5a3c09ce52f9 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/create.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/create.test.ts @@ -105,11 +105,12 @@ describe("cloudchamber create", () => { Create a new deployment GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --image Image to use for your deployment [string] diff --git a/packages/wrangler/src/__tests__/cloudchamber/curl.test.ts b/packages/wrangler/src/__tests__/cloudchamber/curl.test.ts index a401912a4a80..5d663bbb1a14 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/curl.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/curl.test.ts @@ -39,11 +39,12 @@ describe("cloudchamber curl", () => { path [string] [required] [default: \\"/\\"] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS -H, --header Add headers in the form of --header : [array] diff --git a/packages/wrangler/src/__tests__/cloudchamber/delete.test.ts b/packages/wrangler/src/__tests__/cloudchamber/delete.test.ts index 4048b970394d..4d6ae4215741 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/delete.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/delete.test.ts @@ -35,11 +35,12 @@ describe("cloudchamber delete", () => { deploymentId deployment you want to delete [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); diff --git a/packages/wrangler/src/__tests__/cloudchamber/images.test.ts b/packages/wrangler/src/__tests__/cloudchamber/images.test.ts index 0fc9608ef115..e7b96dc09180 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/images.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/images.test.ts @@ -42,11 +42,12 @@ describe("cloudchamber image", () => { wrangler cloudchamber registries list list registries configured for this account GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -188,11 +189,12 @@ describe("cloudchamber image list", () => { List images in the Cloudflare managed registry GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --filter Regex to filter results [string] diff --git a/packages/wrangler/src/__tests__/cloudchamber/list.test.ts b/packages/wrangler/src/__tests__/cloudchamber/list.test.ts index d9eaae850229..d00d9bc553f8 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/list.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/list.test.ts @@ -36,11 +36,12 @@ describe("cloudchamber list", () => { This means that 'list' will only showcase deployments that contain this ID prefix [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --location Filter deployments by location [string] diff --git a/packages/wrangler/src/__tests__/cloudchamber/modify.test.ts b/packages/wrangler/src/__tests__/cloudchamber/modify.test.ts index 0722f2c068fd..9f1b2a3c6c65 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/modify.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/modify.test.ts @@ -73,11 +73,12 @@ describe("cloudchamber modify", () => { deploymentId The deployment you want to modify [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --var Container environment variables [array] diff --git a/packages/wrangler/src/__tests__/containers/delete.test.ts b/packages/wrangler/src/__tests__/containers/delete.test.ts index ac2b752abcfd..30e35119f18b 100644 --- a/packages/wrangler/src/__tests__/containers/delete.test.ts +++ b/packages/wrangler/src/__tests__/containers/delete.test.ts @@ -34,11 +34,12 @@ describe("containers delete", () => { ID id of the containers to delete [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); diff --git a/packages/wrangler/src/__tests__/containers/info.test.ts b/packages/wrangler/src/__tests__/containers/info.test.ts index 12111d872ee6..29138e93fd39 100644 --- a/packages/wrangler/src/__tests__/containers/info.test.ts +++ b/packages/wrangler/src/__tests__/containers/info.test.ts @@ -35,11 +35,12 @@ describe("containers info", () => { ID id of the containers to view [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); diff --git a/packages/wrangler/src/__tests__/containers/list.test.ts b/packages/wrangler/src/__tests__/containers/list.test.ts index db5b822d9479..87acd22a7c2f 100644 --- a/packages/wrangler/src/__tests__/containers/list.test.ts +++ b/packages/wrangler/src/__tests__/containers/list.test.ts @@ -30,11 +30,12 @@ describe("containers list", () => { List containers GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); diff --git a/packages/wrangler/src/__tests__/d1/d1.test.ts b/packages/wrangler/src/__tests__/d1/d1.test.ts index 7c800d656b67..2e35a325d53d 100644 --- a/packages/wrangler/src/__tests__/d1/d1.test.ts +++ b/packages/wrangler/src/__tests__/d1/d1.test.ts @@ -28,11 +28,12 @@ describe("d1", () => { wrangler d1 migrations Interact with D1 migrations GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -64,11 +65,12 @@ describe("d1", () => { wrangler d1 migrations Interact with D1 migrations GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -87,11 +89,12 @@ describe("d1", () => { wrangler d1 migrations apply Apply D1 migrations GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -108,11 +111,12 @@ describe("d1", () => { wrangler d1 time-travel restore Restore a database back to a specific point-in-time GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); }); diff --git a/packages/wrangler/src/__tests__/deployments.test.ts b/packages/wrangler/src/__tests__/deployments.test.ts index db1f16d82ba0..432b5056a26a 100644 --- a/packages/wrangler/src/__tests__/deployments.test.ts +++ b/packages/wrangler/src/__tests__/deployments.test.ts @@ -60,11 +60,12 @@ describe("deployments", () => { wrangler deployments status View the current state of your production GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); diff --git a/packages/wrangler/src/__tests__/dev.test.ts b/packages/wrangler/src/__tests__/dev.test.ts index 5ab4d2453e50..ea90fa9aea1a 100644 --- a/packages/wrangler/src/__tests__/dev.test.ts +++ b/packages/wrangler/src/__tests__/dev.test.ts @@ -1060,6 +1060,66 @@ describe.sequential("wrangler dev", () => { __DOT_ENV_TEST_CUSTOM_BUILD_VAR_LOCAL=default-local" `); }); + + it("should prefer to load environment variables from a custom path `.env` if `--env-file` is set", async () => { + fs.mkdirSync("other", { recursive: true }); + fs.writeFileSync( + "other/.env", + dedent` + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_2=other-2 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=other-3 + ` + ); + + // This file will not be loaded because `--env-file` is set for it. + fs.writeFileSync( + "other/.env.local", + dedent` + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_1=other-local-1 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=other-local-3 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_LOCAL=other-local + ` + ); + + await runWranglerUntilConfig("dev --env-file other/.env"); + expect(extractCustomBuildLogs(std.out)).toMatchInlineSnapshot(` + " + Running: node ./build.js + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_2=other-2 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=other-3" + `); + }); + + it("should prefer to load environment variables from a custom path `.env` if multiple `--env-file` is set", async () => { + fs.mkdirSync("other", { recursive: true }); + fs.writeFileSync( + "other/.env", + dedent` + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_2=other-2 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=other-3 + ` + ); + fs.writeFileSync( + "other/.env.local", + dedent` + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_1=other-local-1 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=other-local-3 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_LOCAL=other-local + ` + ); + + await runWranglerUntilConfig( + "dev --env-file other/.env --env-file other/.env.local" + ); + expect(extractCustomBuildLogs(std.out)).toMatchInlineSnapshot(` + " + Running: node ./build.js + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_1=other-local-1 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_2=other-2 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_3=other-local-3 + __DOT_ENV_TEST_CUSTOM_BUILD_VAR_LOCAL=other-local" + `); + }); }); }); @@ -1652,6 +1712,67 @@ describe.sequential("wrangler dev", () => { 'env.CLOUDFLARE_INCLUDE_PROCESS_ENV ("(hidden)")' ); }); + + it("should get local dev `vars` from appropriate `.env.` files when --env-file is set", async () => { + fs.mkdirSync("other", { recursive: true }); + fs.writeFileSync( + "other/.env", + dedent` + __DOT_ENV_LOCAL_DEV_VAR_2=custom-2 + __DOT_ENV_LOCAL_DEV_VAR_3=custom-3 + ` + ); + fs.writeFileSync( + "other/.env.local", + dedent` + __DOT_ENV_LOCAL_DEV_VAR_1=custom-local-1 + __DOT_ENV_LOCAL_DEV_VAR_3=custom-local-3 + __DOT_ENV_LOCAL_DEV_VAR_LOCAL=custom-local + ` + ); + + await runWranglerUntilConfig("dev --env-file=other/.env"); + expect(extractUsingVars(std.out)).toMatchInlineSnapshot( + `"Using vars defined in other/.env"` + ); + expect(extractBindings(std.out)).toMatchInlineSnapshot(` + "env.__DOT_ENV_LOCAL_DEV_VAR_2 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_3 (\\"(hidden)\\") Environment Variable local" + `); + }); + + it("should get local dev `vars` from appropriate `.env.` files when multiple --env-file options are set", async () => { + fs.mkdirSync("other", { recursive: true }); + fs.writeFileSync( + "other/.env", + dedent` + __DOT_ENV_LOCAL_DEV_VAR_2=custom-2 + __DOT_ENV_LOCAL_DEV_VAR_3=custom-3 + ` + ); + fs.writeFileSync( + "other/.env.local", + dedent` + __DOT_ENV_LOCAL_DEV_VAR_1=custom-local-1 + __DOT_ENV_LOCAL_DEV_VAR_3=custom-local-3 + __DOT_ENV_LOCAL_DEV_VAR_LOCAL=custom-local + ` + ); + + await runWranglerUntilConfig( + "dev --env-file=other/.env --env-file=other/.env.local" + ); + expect(extractUsingVars(std.out)).toMatchInlineSnapshot(` + "Using vars defined in other/.env + Using vars defined in other/.env.local" + `); + expect(extractBindings(std.out)).toMatchInlineSnapshot(` + "env.__DOT_ENV_LOCAL_DEV_VAR_1 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_2 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_3 (\\"(hidden)\\") Environment Variable local + env.__DOT_ENV_LOCAL_DEV_VAR_LOCAL (\\"(hidden)\\") Environment Variable local" + `); + }); }); describe("serve static assets", () => { diff --git a/packages/wrangler/src/__tests__/docs.test.ts b/packages/wrangler/src/__tests__/docs.test.ts index 99c3c24433c0..e4ca6fb75813 100644 --- a/packages/wrangler/src/__tests__/docs.test.ts +++ b/packages/wrangler/src/__tests__/docs.test.ts @@ -47,11 +47,12 @@ describe("wrangler docs", () => { search Enter search terms (e.g. the wrangler command) you want to know more about [array] [default: []] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS -y, --yes Takes you to the docs, even if search fails [boolean]" diff --git a/packages/wrangler/src/__tests__/hyperdrive.test.ts b/packages/wrangler/src/__tests__/hyperdrive.test.ts index 0b343fe1b0c2..3633c0312d34 100644 --- a/packages/wrangler/src/__tests__/hyperdrive.test.ts +++ b/packages/wrangler/src/__tests__/hyperdrive.test.ts @@ -37,11 +37,12 @@ describe("hyperdrive help", () => { wrangler hyperdrive update Update a Hyperdrive config GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -69,11 +70,12 @@ describe("hyperdrive help", () => { wrangler hyperdrive update Update a Hyperdrive config GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); }); diff --git a/packages/wrangler/src/__tests__/index.test.ts b/packages/wrangler/src/__tests__/index.test.ts index cc0c83573b0f..66958b8c0f69 100644 --- a/packages/wrangler/src/__tests__/index.test.ts +++ b/packages/wrangler/src/__tests__/index.test.ts @@ -70,11 +70,12 @@ describe("wrangler", () => { wrangler whoami 🕵️ Retrieve your user information GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] Please report any issues to https://github.com/cloudflare/workers-sdk/issues/new/choose" `); @@ -130,11 +131,12 @@ describe("wrangler", () => { wrangler whoami 🕵️ Retrieve your user information GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] Please report any issues to https://github.com/cloudflare/workers-sdk/issues/new/choose" `); @@ -201,11 +203,12 @@ describe("wrangler", () => { wrangler secret bulk [file] Bulk upload secrets for a Worker GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -224,11 +227,12 @@ describe("wrangler", () => { wrangler kv namespace rename [old-name] Rename a KV namespace GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -247,11 +251,12 @@ describe("wrangler", () => { wrangler kv key delete Remove a single key value pair from the given namespace GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -269,11 +274,12 @@ describe("wrangler", () => { wrangler kv bulk delete Delete multiple key-value pairs from a namespace GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -290,11 +296,12 @@ describe("wrangler", () => { wrangler r2 bucket Manage R2 buckets GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); }); diff --git a/packages/wrangler/src/__tests__/kv.test.ts b/packages/wrangler/src/__tests__/kv.test.ts index 1cf3611d9579..b0a21107032d 100644 --- a/packages/wrangler/src/__tests__/kv.test.ts +++ b/packages/wrangler/src/__tests__/kv.test.ts @@ -48,11 +48,12 @@ describe("wrangler", () => { wrangler kv bulk Interact with multiple Workers KV key-value pairs at once GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -70,11 +71,12 @@ describe("wrangler", () => { wrangler kv bulk Interact with multiple Workers KV key-value pairs at once GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -99,11 +101,12 @@ describe("wrangler", () => { wrangler kv bulk Interact with multiple Workers KV key-value pairs at once GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -144,11 +147,12 @@ describe("wrangler", () => { namespace The name of the new namespace [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --preview Interact with a preview namespace [boolean]" @@ -176,11 +180,12 @@ describe("wrangler", () => { namespace The name of the new namespace [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --preview Interact with a preview namespace [boolean]" @@ -450,11 +455,12 @@ describe("wrangler", () => { old-name The current name (title) of the namespace to rename [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --namespace-id The id of the namespace to rename [string] @@ -841,11 +847,12 @@ describe("wrangler", () => { value The value to write [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --binding The binding name to the namespace to write to [string] @@ -884,11 +891,12 @@ describe("wrangler", () => { value The value to write [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --binding The binding name to the namespace to write to [string] @@ -929,11 +937,12 @@ describe("wrangler", () => { value The value to write [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --binding The binding name to the namespace to write to [string] @@ -972,11 +981,12 @@ describe("wrangler", () => { value The value to write [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --binding The binding name to the namespace to write to [string] @@ -1015,11 +1025,12 @@ describe("wrangler", () => { value The value to write [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --binding The binding name to the namespace to write to [string] @@ -1060,11 +1071,12 @@ describe("wrangler", () => { value The value to write [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --binding The binding name to the namespace to write to [string] @@ -1451,11 +1463,12 @@ describe("wrangler", () => { key The key value to get. [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --binding The binding name to the namespace to get from [string] @@ -1489,11 +1502,12 @@ describe("wrangler", () => { key The key value to get. [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --binding The binding name to the namespace to get from [string] @@ -1528,11 +1542,12 @@ describe("wrangler", () => { key The key value to get. [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --binding The binding name to the namespace to get from [string] diff --git a/packages/wrangler/src/__tests__/mtls-certificates.test.ts b/packages/wrangler/src/__tests__/mtls-certificates.test.ts index f4a27bb5a99e..3be6ea71bbb4 100644 --- a/packages/wrangler/src/__tests__/mtls-certificates.test.ts +++ b/packages/wrangler/src/__tests__/mtls-certificates.test.ts @@ -402,11 +402,12 @@ describe("wrangler", () => { wrangler mtls-certificate delete Delete an mTLS certificate GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); }); diff --git a/packages/wrangler/src/__tests__/pages/deploy.test.ts b/packages/wrangler/src/__tests__/pages/deploy.test.ts index dcc705f35f5b..f976bb0554b0 100644 --- a/packages/wrangler/src/__tests__/pages/deploy.test.ts +++ b/packages/wrangler/src/__tests__/pages/deploy.test.ts @@ -64,9 +64,10 @@ describe("pages deploy", () => { directory The directory of static files to upload [string] GLOBAL FLAGS - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --project-name The name of the project you want to deploy to [string] diff --git a/packages/wrangler/src/__tests__/pages/pages.test.ts b/packages/wrangler/src/__tests__/pages/pages.test.ts index 7aed2a4551a1..00a8ca5094fd 100644 --- a/packages/wrangler/src/__tests__/pages/pages.test.ts +++ b/packages/wrangler/src/__tests__/pages/pages.test.ts @@ -32,9 +32,10 @@ describe("pages", () => { wrangler pages download Download settings from your project GLOBAL FLAGS - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -52,9 +53,10 @@ describe("pages", () => { command The proxy command to run [deprecated] [string] GLOBAL FLAGS - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --compatibility-date Date to use for compatibility checks [string] @@ -100,9 +102,10 @@ describe("pages", () => { wrangler pages project delete Delete a Cloudflare Pages project GLOBAL FLAGS - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -123,9 +126,10 @@ describe("pages", () => { wrangler pages deployment tail [deployment] Start a tailing session for a project's deployment and livestream logs from your Functions GLOBAL FLAGS - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -142,9 +146,10 @@ describe("pages", () => { directory The directory of static files to upload [string] GLOBAL FLAGS - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --project-name The name of the project you want to deploy to [string] @@ -174,9 +179,10 @@ describe("pages", () => { wrangler pages secret list List all secrets for a Pages project GLOBAL FLAGS - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -193,9 +199,10 @@ describe("pages", () => { wrangler pages download config [projectName] Download your Pages project config as a Wrangler configuration file [experimental] GLOBAL FLAGS - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); diff --git a/packages/wrangler/src/__tests__/pipelines.test.ts b/packages/wrangler/src/__tests__/pipelines.test.ts index 8a6e982aadcd..2f54df13f977 100644 --- a/packages/wrangler/src/__tests__/pipelines.test.ts +++ b/packages/wrangler/src/__tests__/pipelines.test.ts @@ -284,11 +284,12 @@ describe("pipelines", () => { wrangler pipelines delete Delete a pipeline [open-beta] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -327,11 +328,12 @@ describe("pipelines", () => { pipeline The name of the new pipeline [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); diff --git a/packages/wrangler/src/__tests__/pubsub.test.ts b/packages/wrangler/src/__tests__/pubsub.test.ts index 0efc740ddc83..84d010156b56 100644 --- a/packages/wrangler/src/__tests__/pubsub.test.ts +++ b/packages/wrangler/src/__tests__/pubsub.test.ts @@ -35,11 +35,12 @@ describe("wrangler", () => { wrangler pubsub broker Interact with your Pub/Sub Brokers GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] 👷🏽 'wrangler pubsub ...' commands are currently in private beta. If your account isn't authorized, commands will fail. Visit the Pub/Sub docs for more info: https://developers.cloudflare.com/pub-sub/", "warn": "", @@ -68,11 +69,12 @@ describe("wrangler", () => { wrangler pubsub namespace describe Describe a Pub/Sub Namespace GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] 👷🏽 'wrangler pubsub ...' commands are currently in private beta. If your account isn't authorized, commands will fail. Visit the Pub/Sub docs for more info: https://developers.cloudflare.com/pub-sub/", "warn": "", @@ -196,11 +198,12 @@ describe("wrangler", () => { wrangler pubsub broker public-keys Show the public keys used for verifying on-publish hooks and credentials for a Broker. GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] 👷🏽 'wrangler pubsub ...' commands are currently in private beta. If your account isn't authorized, commands will fail. Visit the Pub/Sub docs for more info: https://developers.cloudflare.com/pub-sub/", "warn": "", diff --git a/packages/wrangler/src/__tests__/queues.test.ts b/packages/wrangler/src/__tests__/queues.test.ts index a95418156e01..4f0e4cc776e6 100644 --- a/packages/wrangler/src/__tests__/queues.test.ts +++ b/packages/wrangler/src/__tests__/queues.test.ts @@ -40,11 +40,12 @@ describe("wrangler", () => { wrangler queues purge Purge messages from a Queue GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -114,11 +115,12 @@ describe("wrangler", () => { List Queues GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --page Page number for pagination [number]" @@ -262,11 +264,12 @@ describe("wrangler", () => { name The name of the queue [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --delivery-delay-secs How long a published message should be delayed for, in seconds. Must be between 0 and 42300 [number] [default: 0] @@ -482,11 +485,12 @@ describe("wrangler", () => { name The name of the queue [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --delivery-delay-secs How long a published message should be delayed for, in seconds. Must be between 0 and 42300 [number] @@ -636,11 +640,12 @@ describe("wrangler", () => { name The name of the queue [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -705,11 +710,12 @@ describe("wrangler", () => { wrangler queues consumer worker Configure Queue Worker Consumers GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -753,11 +759,12 @@ describe("wrangler", () => { script-name Name of the consumer script [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --batch-size Maximum number of messages per batch [number] @@ -1075,11 +1082,12 @@ describe("wrangler", () => { script-name Name of the consumer script [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -1463,11 +1471,12 @@ describe("wrangler", () => { wrangler queues consumer http remove Remove a Queue HTTP Pull Consumer GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -1510,11 +1519,12 @@ describe("wrangler", () => { queue-name Name of the queue for the consumer [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --batch-size Maximum number of messages per batch [number] @@ -1641,11 +1651,12 @@ describe("wrangler", () => { queue-name Name of the queue for the consumer [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -1729,11 +1740,12 @@ describe("wrangler", () => { name The name of the queue [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); it("should return queue info with worker producers when the queue has workers configured as producers", async () => { @@ -1892,11 +1904,12 @@ describe("wrangler", () => { name The name of the queue [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -2002,11 +2015,12 @@ describe("wrangler", () => { name The name of the queue [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -2104,11 +2118,12 @@ describe("wrangler", () => { name The name of the queue [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --force Skip the confirmation dialog and forcefully purge the Queue [boolean]" diff --git a/packages/wrangler/src/__tests__/r2.test.ts b/packages/wrangler/src/__tests__/r2.test.ts index f80cde792913..05217cc8adb7 100644 --- a/packages/wrangler/src/__tests__/r2.test.ts +++ b/packages/wrangler/src/__tests__/r2.test.ts @@ -101,11 +101,12 @@ describe("r2", () => { wrangler r2 bucket Manage R2 buckets GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -130,11 +131,12 @@ describe("r2", () => { wrangler r2 bucket Manage R2 buckets GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -166,11 +168,12 @@ describe("r2", () => { wrangler r2 bucket lock Manage lock rules for an R2 bucket GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -207,11 +210,12 @@ describe("r2", () => { wrangler r2 bucket lock Manage lock rules for an R2 bucket GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -315,11 +319,12 @@ describe("r2", () => { name The name of the new bucket [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --location The optional location hint that determines geographic placement of the R2 bucket [string] [choices: \\"weur\\", \\"eeur\\", \\"apac\\", \\"wnam\\", \\"enam\\", \\"oc\\"] @@ -349,11 +354,12 @@ describe("r2", () => { name The name of the new bucket [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --location The optional location hint that determines geographic placement of the R2 bucket [string] [choices: \\"weur\\", \\"eeur\\", \\"apac\\", \\"wnam\\", \\"enam\\", \\"oc\\"] @@ -472,11 +478,12 @@ describe("r2", () => { wrangler r2 bucket update storage-class Update the default storage class of an existing R2 bucket GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); expect(std.err).toMatchInlineSnapshot(` "X [ERROR] Unknown argument: foo @@ -502,11 +509,12 @@ describe("r2", () => { name The name of the existing bucket [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS -J, --jurisdiction The jurisdiction of the bucket to be updated [string] @@ -568,11 +576,12 @@ describe("r2", () => { bucket The name of the bucket to delete [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS -J, --jurisdiction The jurisdiction where the bucket exists [string]" @@ -632,11 +641,12 @@ describe("r2", () => { bucket The name of the bucket to delete [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS -J, --jurisdiction The jurisdiction where the bucket exists [string]" @@ -700,11 +710,12 @@ describe("r2", () => { wrangler r2 bucket sippy get Check the status of Sippy on an R2 bucket GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -792,11 +803,12 @@ describe("r2", () => { name The name of the bucket [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS -J, --jurisdiction The jurisdiction where the bucket exists [string] @@ -836,11 +848,12 @@ describe("r2", () => { name The name of the bucket [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS -J, --jurisdiction The jurisdiction where the bucket exists [string]" @@ -888,11 +901,12 @@ describe("r2", () => { name The name of the bucket [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS -J, --jurisdiction The jurisdiction where the bucket exists [string]" @@ -955,11 +969,12 @@ describe("r2", () => { wrangler r2 bucket catalog get Get the status of the data catalog for an R2 bucket [open-beta] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -1011,11 +1026,12 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" bucket The name of the bucket to enable [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); expect(std.err).toMatchInlineSnapshot(` "X [ERROR] Not enough non-option arguments: got 0, need at least 1 @@ -1043,11 +1059,12 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" bucket The name of the bucket to disable the data catalog for [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); expect(std.err).toMatchInlineSnapshot(` "X [ERROR] Not enough non-option arguments: got 0, need at least 1 @@ -1132,11 +1149,12 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" bucket The name of the R2 bucket whose data catalog status to retrieve [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); expect(std.err).toMatchInlineSnapshot(` "X [ERROR] Not enough non-option arguments: got 0, need at least 1 @@ -1352,11 +1370,12 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" bucket The name of the R2 bucket to get event notification rules for [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS -J, --jurisdiction The jurisdiction where the bucket exists [string]" @@ -1713,11 +1732,12 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" bucket The name of the R2 bucket to create an event notification rule for [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --event-types, --event-type The type of event(s) that will emit event notifications [array] [required] [choices: \\"object-create\\", \\"object-delete\\"] @@ -1872,11 +1892,12 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" bucket The name of the R2 bucket to delete an event notification rule for [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --queue The name of the queue that corresponds to the event notification rule. If no rule is provided, all event notification rules associated with the bucket and queue will be deleted [string] [required] @@ -3201,11 +3222,12 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" wrangler r2 object delete Delete an object in an R2 bucket GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); describe("remote", () => { diff --git a/packages/wrangler/src/__tests__/secrets-store.test.ts b/packages/wrangler/src/__tests__/secrets-store.test.ts index 4b3804ee9b42..753b5d4e70d5 100644 --- a/packages/wrangler/src/__tests__/secrets-store.test.ts +++ b/packages/wrangler/src/__tests__/secrets-store.test.ts @@ -25,20 +25,21 @@ describe("secrets-store help", () => { expect(std.err).toMatchInlineSnapshot(`""`); expect(std.out).toMatchInlineSnapshot(` - "wrangler secrets-store + "wrangler secrets-store -🔐 Manage the Secrets Store [alpha] + 🔐 Manage the Secrets Store [alpha] -COMMANDS - wrangler secrets-store store 🔐 Manage Stores within the Secrets Store [alpha] - wrangler secrets-store secret 🔐 Manage Secrets within the Secrets Store [alpha] + COMMANDS + wrangler secrets-store store 🔐 Manage Stores within the Secrets Store [alpha] + wrangler secrets-store secret 🔐 Manage Secrets within the Secrets Store [alpha] -GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + GLOBAL FLAGS + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -53,21 +54,22 @@ GLOBAL FLAGS " `); expect(std.out).toMatchInlineSnapshot(` - " -wrangler secrets-store - -🔐 Manage the Secrets Store [alpha] - -COMMANDS - wrangler secrets-store store 🔐 Manage Stores within the Secrets Store [alpha] - wrangler secrets-store secret 🔐 Manage Secrets within the Secrets Store [alpha] - -GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + " + wrangler secrets-store + + 🔐 Manage the Secrets Store [alpha] + + COMMANDS + wrangler secrets-store store 🔐 Manage Stores within the Secrets Store [alpha] + wrangler secrets-store secret 🔐 Manage Secrets within the Secrets Store [alpha] + + GLOBAL FLAGS + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); }); diff --git a/packages/wrangler/src/__tests__/vectorize/vectorize.test.ts b/packages/wrangler/src/__tests__/vectorize/vectorize.test.ts index 37e2ec31df62..39a7130ee341 100644 --- a/packages/wrangler/src/__tests__/vectorize/vectorize.test.ts +++ b/packages/wrangler/src/__tests__/vectorize/vectorize.test.ts @@ -39,11 +39,12 @@ describe("vectorize help", () => { wrangler vectorize delete-metadata-index Delete metadata indexes GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -79,11 +80,12 @@ describe("vectorize help", () => { wrangler vectorize delete-metadata-index Delete metadata indexes GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -107,11 +109,12 @@ describe("vectorize help", () => { name The name of the Vectorize index. [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --json Return output as clean JSON [boolean] [default: false] @@ -139,11 +142,12 @@ describe("vectorize help", () => { name The name of the Vectorize index [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --vector Vector to query the Vectorize Index [number] diff --git a/packages/wrangler/src/__tests__/versions/versions.help.test.ts b/packages/wrangler/src/__tests__/versions/versions.help.test.ts index 45bde39cbddf..48e376df89e3 100644 --- a/packages/wrangler/src/__tests__/versions/versions.help.test.ts +++ b/packages/wrangler/src/__tests__/versions/versions.help.test.ts @@ -23,11 +23,12 @@ describe("versions --help", () => { wrangler versions secret Generate a secret that can be referenced in a Worker GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); }); @@ -54,11 +55,12 @@ describe("versions subhelp", () => { wrangler versions secret Generate a secret that can be referenced in a Worker GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); }); diff --git a/packages/wrangler/src/__tests__/worker-namespace.test.ts b/packages/wrangler/src/__tests__/worker-namespace.test.ts index e0009008f6bb..165ff695b6ee 100644 --- a/packages/wrangler/src/__tests__/worker-namespace.test.ts +++ b/packages/wrangler/src/__tests__/worker-namespace.test.ts @@ -42,11 +42,12 @@ describe("dispatch-namespace", () => { wrangler dispatch-namespace rename Rename a dispatch namespace GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]", + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]", "warn": "", } `); @@ -95,11 +96,12 @@ describe("dispatch-namespace", () => { name Name of the dispatch namespace [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -146,11 +148,12 @@ describe("dispatch-namespace", () => { name Name of the dispatch namespace [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -206,11 +209,12 @@ describe("dispatch-namespace", () => { name Name of the dispatch namespace [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); @@ -317,11 +321,12 @@ describe("dispatch-namespace", () => { newName New name of the dispatch namespace [string] [required] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" `); }); diff --git a/packages/wrangler/src/__tests__/workflows.test.ts b/packages/wrangler/src/__tests__/workflows.test.ts index 1af1a75b0af0..ee907371723e 100644 --- a/packages/wrangler/src/__tests__/workflows.test.ts +++ b/packages/wrangler/src/__tests__/workflows.test.ts @@ -125,11 +125,12 @@ describe("wrangler workflows", () => { wrangler workflows instances Manage Workflow instances GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" ` ); }); @@ -156,11 +157,12 @@ describe("wrangler workflows", () => { wrangler workflows instances resume Resume a workflow instance GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean]" + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean]" ` ); }); diff --git a/packages/wrangler/src/api/dev.ts b/packages/wrangler/src/api/dev.ts index fbe39b509235..b972d249398e 100644 --- a/packages/wrangler/src/api/dev.ts +++ b/packages/wrangler/src/api/dev.ts @@ -15,6 +15,7 @@ import type { RequestInfo, RequestInit, Response } from "undici"; export interface Unstable_DevOptions { config?: string; // Path to .toml configuration file, relative to cwd env?: string; // Environment to use for operations, and for selecting .env and .dev.vars files + envFiles?: string[]; // Paths to .env file to load, relative to cwd ip?: string; // IP address to listen on port?: number; // Port to listen on bundle?: boolean; // Set to false to skip internal build steps and directly deploy script @@ -183,6 +184,7 @@ export async function unstable_dev( }, config: options?.config, env: options?.env, + envFile: options?.envFiles, processEntrypoint, additionalModules, bundle: options?.bundle, diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 6efa41151ca4..77bdaa86d6f3 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -56,6 +56,17 @@ export type GetPlatformProxyOptions = { * point to a valid file on the filesystem */ configPath?: string; + /** + * Paths to `.env` file to load environment variables from. + * + * If not specified, the default behavior: + * - look for a `.env` file in the same directory as the Wrangler configuration file, or in the current working + * directory if no Wrangler configuration file is specified. + * - also look for a `.env.local` file in the same directory as the `.env` file. + * - if the `environment` option is specified, also look for `.env.` and `.env..local` + * files in the same directory as the `.env` file. + */ + envFiles?: string[]; /** * Indicates if and where to persist the bindings data, if not present or `true` it defaults to the same location * used by wrangler: `.wrangler/state/v3` (so that the same data can be easily used by the caller and wrangler). @@ -183,6 +194,7 @@ async function getMiniflareOptionsFromConfig(args: { const bindings = getBindings( config, options.environment, + options.envFiles, true, {}, remoteBindingsEnabled @@ -350,6 +362,7 @@ export function unstable_getMiniflareWorkerOptions( configOrConfigPath: string | Config, env?: string, options?: { + envFiles?: string[]; imagesLocalMode?: boolean; remoteProxyConnectionString?: RemoteProxyConnectionString; remoteBindingsEnabled?: boolean; @@ -375,7 +388,7 @@ export function unstable_getMiniflareWorkerOptions( const containerDOClassNames = new Set( config.containers?.map((c) => c.class_name) ); - const bindings = getBindings(config, env, true, {}, true); + const bindings = getBindings(config, env, options?.envFiles, true, {}, true); const { bindingOptions, externalWorkers } = buildMiniflareBindingOptions( { name: config.name, diff --git a/packages/wrangler/src/api/startDevWorker/ConfigController.ts b/packages/wrangler/src/api/startDevWorker/ConfigController.ts index 07d27e361ed3..e31125c5af30 100644 --- a/packages/wrangler/src/api/startDevWorker/ConfigController.ts +++ b/packages/wrangler/src/api/startDevWorker/ConfigController.ts @@ -177,6 +177,7 @@ async function resolveBindings( const bindings = getBindings( config, input.env, + input.envFiles, !input.dev?.remote, { kv: extractBindingsOfType("kv_namespace", input.bindings), @@ -323,6 +324,7 @@ async function resolveConfig( sendMetrics: input.sendMetrics ?? config.send_metrics, triggers: await resolveTriggers(config, input), env: input.env, + envFiles: input.envFiles, build: { alias: input.build?.alias ?? config.alias, additionalModules: input.build?.additionalModules ?? [], diff --git a/packages/wrangler/src/api/startDevWorker/types.ts b/packages/wrangler/src/api/startDevWorker/types.ts index f03fe1a0f486..37d5ec059b9b 100644 --- a/packages/wrangler/src/api/startDevWorker/types.ts +++ b/packages/wrangler/src/api/startDevWorker/types.ts @@ -84,6 +84,12 @@ export interface StartDevWorkerInput { env?: string; + /** + * The paths to the .env files to load for this worker, relative to the worker's directory. + * If not specified, defaults to the standard `.env` files, in the wrangler config directory or current working directory if no wrangler config is present. + */ + envFiles?: string[]; + /** The bindings available to the worker. The specified bindind type will be exposed to the worker on the `env` object under the same key. */ bindings?: Record; // Type level constraint for bindings not sharing names migrations?: DurableObjectMigration[]; diff --git a/packages/wrangler/src/dev.ts b/packages/wrangler/src/dev.ts index dea2c21f88b8..6e3701abc37d 100644 --- a/packages/wrangler/src/dev.ts +++ b/packages/wrangler/src/dev.ts @@ -485,6 +485,7 @@ async function setupDevEnv( pattern: r, })), env: args.env, + envFiles: args.envFile, build: { bundle: args.bundle !== undefined ? args.bundle : undefined, define: collectKeyValues(args.define), @@ -867,6 +868,7 @@ function getResolvedSiteAssetPaths( export function getBindings( configParam: Config, env: string | undefined, + envFiles: string[] | undefined, local: boolean, args: AdditionalDevProps, remoteBindingsEnabled = getFlag("REMOTE_BINDINGS") @@ -1040,7 +1042,12 @@ export function getBindings( // non-inheritable fields vars: { // Use a copy of combinedVars since we're modifying it later - ...getVarsForDev(configParam, env), + ...getVarsForDev( + configParam.userConfigPath, + envFiles, + configParam.vars, + env + ), ...args.vars, }, durable_objects: { diff --git a/packages/wrangler/src/dev/dev-vars.ts b/packages/wrangler/src/dev/dev-vars.ts index e326ce9c0b84..769ce85bce87 100644 --- a/packages/wrangler/src/dev/dev-vars.ts +++ b/packages/wrangler/src/dev/dev-vars.ts @@ -27,13 +27,13 @@ import type { Config } from "../config"; * */ export function getVarsForDev( - config: Pick, + configPath: string | undefined, + envFilePaths: string[] | undefined, + vars: Config["vars"], env: string | undefined, silent = false ): Config["vars"] { - const configDir = path.resolve( - config.userConfigPath ? path.dirname(config.userConfigPath) : "." - ); + const configDir = path.resolve(configPath ? path.dirname(configPath) : "."); // First, try to load from .dev.vars const devVarsPath = path.resolve(configDir, ".dev.vars"); @@ -44,20 +44,20 @@ export function getVarsForDev( logger.log(`Using vars defined in ${devVarsRelativePath}`); } return { - ...config.vars, + ...vars, ...loaded.parsed, }; } else { - // If no .dev.vars files load vars from .env files in the configuration directory. - const dotEnvVars = loadDotEnv( - getDefaultEnvPaths(path.resolve(path.join(configDir, ".env")), env), - { - includeProcessEnv: getCloudflareIncludeProcessEnvFromEnv(), - silent, - } - ); + // If no .dev.vars files load vars from those in `envFilePaths` if defined or default .env files in the configuration directory. + const resolvedEnvFilePaths = ( + envFilePaths ?? getDefaultEnvPaths(".env", env) + ).map((p) => path.resolve(path.join(configDir, p))); + const dotEnvVars = loadDotEnv(resolvedEnvFilePaths, { + includeProcessEnv: getCloudflareIncludeProcessEnvFromEnv(), + silent, + }); return { - ...config.vars, + ...vars, ...dotEnvVars, }; } diff --git a/packages/wrangler/src/index.ts b/packages/wrangler/src/index.ts index 49abd521ccf3..e22d2fd0cdcf 100644 --- a/packages/wrangler/src/index.ts +++ b/packages/wrangler/src/index.ts @@ -402,6 +402,13 @@ export function createCLIParser(argv: string[]) { type: "string", requiresArg: true, }) + .option("env-file", { + describe: + "Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones", + type: "string", + array: true, + requiresArg: true, + }) .check(demandSingleValue("env")) .option("experimental-json-config", { alias: "j", @@ -421,12 +428,15 @@ export function createCLIParser(argv: string[]) { return true; }) .check((args) => { - // Grab locally specified env params from `.env` file + // Set process environment params from `.env` files if available. process.env = - loadDotEnv(getDefaultEnvPaths(resolve(".env"), args.env), { - includeProcessEnv: true, - silent: true, - }) ?? process.env; + loadDotEnv( + args["env-file"] ?? getDefaultEnvPaths(resolve(".env"), args.env), + { + includeProcessEnv: true, + silent: true, + } + ) ?? process.env; // Write a session entry to the output file (if there is one). writeOutput({ @@ -464,7 +474,7 @@ export function createCLIParser(argv: string[]) { "Examples:": `${chalk.bold("EXAMPLES")}`, }); wrangler.group( - ["config", "cwd", "env", "help", "version"], + ["config", "cwd", "env", "env-file", "help", "version"], `${chalk.bold("GLOBAL FLAGS")}` ); wrangler.help("help", "Show help").alias("h", "help"); diff --git a/packages/wrangler/src/pages/dev.ts b/packages/wrangler/src/pages/dev.ts index a6aa818f5408..d504eb4256b8 100644 --- a/packages/wrangler/src/pages/dev.ts +++ b/packages/wrangler/src/pages/dev.ts @@ -923,6 +923,7 @@ export const pagesDevCommand = createCommand({ minify: undefined, legacyEnv: undefined, env: undefined, + envFile: undefined, ip, port, inspectorPort, diff --git a/packages/wrangler/src/type-generation/index.ts b/packages/wrangler/src/type-generation/index.ts index 2d815ebd642c..1d7f1d536780 100644 --- a/packages/wrangler/src/type-generation/index.ts +++ b/packages/wrangler/src/type-generation/index.ts @@ -305,10 +305,12 @@ export async function generateEnvTypes( ): Promise<{ envHeader?: string; envTypes?: string }> { const stringKeys: string[] = []; const secrets = getVarsForDev( + config.userConfigPath, + args.envFile, // We do not want `getVarsForDev()` to merge in the standard vars into the dev vars // because we want to be able to work with secrets differently to vars. // So we pass in a fake vars object here. - { ...config, vars: {} }, + {}, args.env, true ) as Record; diff --git a/packages/wrangler/src/yargs-types.ts b/packages/wrangler/src/yargs-types.ts index 47904e8fff86..5a7c9174c720 100644 --- a/packages/wrangler/src/yargs-types.ts +++ b/packages/wrangler/src/yargs-types.ts @@ -9,6 +9,7 @@ export interface CommonYargsOptions { cwd: string | undefined; config: string | undefined; env: string | undefined; + "env-file": string[] | undefined; "experimental-provision": boolean | undefined; "experimental-remote-bindings": boolean | undefined; } From e4a1dba563b9a793329302b28b8bb090dccc67f4 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 14 Jul 2025 13:22:00 +0100 Subject: [PATCH 03/42] Add support for loading local vars from .env files to the vite-plugin --- .../playground/__test-utils__/index.ts | 14 +++- .../dev-vars/__tests__/vars-changes.spec.ts | 37 ++-------- .../playground/dot-env/.env | 4 + .../playground/dot-env/.env.staging | 3 + .../dot-env/.env.with-specified-env | 1 + .../playground/dot-env/.gitignore | 1 + .../dot-env/__tests__/dot-env-loading.spec.ts | 39 ++++++++++ .../dot-env/__tests__/vars-changes.spec.ts | 38 ++++++++++ .../dot-env-loading.spec.ts | 36 +++++++++ .../with-specified-env/vars-changes.spec.ts | 43 +++++++++++ .../playground/dot-env/package.json | 19 +++++ .../playground/dot-env/src/index.ts | 9 +++ .../playground/dot-env/tsconfig.json | 7 ++ .../playground/dot-env/tsconfig.node.json | 8 ++ .../playground/dot-env/tsconfig.worker.json | 4 + .../playground/dot-env/turbo.json | 9 +++ .../playground/dot-env/vite.config.ts | 6 ++ .../dot-env/vite.config.with-specified-env.ts | 7 ++ .../dot-env/worker-configuration.d.ts | 8 ++ .../playground/dot-env/wrangler.jsonc | 8 ++ .../vite-plugin-cloudflare/src/dev-vars.ts | 74 +++++++++---------- packages/vite-plugin-cloudflare/src/index.ts | 16 ++-- .../src/api/integrations/platform/index.ts | 1 + pnpm-lock.yaml | 23 +++++- 24 files changed, 335 insertions(+), 80 deletions(-) create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/.env create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/.env.staging create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/.env.with-specified-env create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/.gitignore create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/__tests__/dot-env-loading.spec.ts create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/dot-env-loading.spec.ts create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/vars-changes.spec.ts create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/package.json create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/src/index.ts create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.json create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.node.json create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.worker.json create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/turbo.json create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/vite.config.ts create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/vite.config.with-specified-env.ts create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/worker-configuration.d.ts create mode 100644 packages/vite-plugin-cloudflare/playground/dot-env/wrangler.jsonc diff --git a/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts b/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts index cc37aaf32e10..7fd42f124600 100644 --- a/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts +++ b/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts @@ -1,4 +1,5 @@ -import { test } from "vitest"; +import fs from "node:fs"; +import { onTestFinished, test } from "vitest"; export * from "../vitest-setup"; export * from "./responses"; @@ -6,3 +7,14 @@ export * from "./responses"; export function failsIf(condition: boolean) { return condition ? test.fails : test; } + +export function mockFileChange( + filePath: string, + mutateFn: (originalContent: string) => string +) { + const originalContent = fs.readFileSync(filePath, "utf-8"); + onTestFinished(() => { + fs.writeFileSync(filePath, originalContent); + }); + fs.writeFileSync(filePath, mutateFn(originalContent)); +} diff --git a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/vars-changes.spec.ts b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/vars-changes.spec.ts index e1898bba5424..ef43666dda59 100644 --- a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/vars-changes.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/vars-changes.spec.ts @@ -1,34 +1,10 @@ -import * as fs from "node:fs"; import * as path from "node:path"; import { expect, test, vi } from "vitest"; -import { getJsonResponse, isBuild } from "../../__test-utils__"; +import { getJsonResponse, isBuild, mockFileChange } from "../../__test-utils__"; test.runIf(!isBuild)( "successfully updates when a var is updated in a .dev.vars file", - async ({ onTestFinished }) => { - const dotDevDotVarsFilePath = path.join(__dirname, "../.dev.vars"); - const originalDotDevDotVars = fs.readFileSync( - dotDevDotVarsFilePath, - "utf-8" - ); - - onTestFinished(async () => { - fs.writeFileSync(dotDevDotVarsFilePath, originalDotDevDotVars); - // We need to ensure that the original config is restored before the next test runs - await vi.waitFor( - async () => { - expect(await getJsonResponse()).toEqual({ - "variables present in .dev.vars": { - MY_DEV_VAR_A: "my .dev.vars variable A", - MY_DEV_VAR_B: "my .dev.vars variable B", - MY_DEV_VAR_C: "my .dev.vars variable C", - }, - }); - }, - { timeout: 5000 } - ); - }); - + async () => { const originalResponse = await getJsonResponse(); expect(originalResponse).toEqual({ "variables present in .dev.vars": { @@ -38,12 +14,13 @@ test.runIf(!isBuild)( }, }); - const updatedDotDevDotVars = originalDotDevDotVars.replace( - /my \.dev\.vars variable/g, - "my .dev.vars UPDATED variable" + mockFileChange(path.join(__dirname, "../.dev.vars"), (content) => + content.replace( + /my \.dev\.vars variable/g, + "my .dev.vars UPDATED variable" + ) ); - fs.writeFileSync(dotDevDotVarsFilePath, updatedDotDevDotVars); await vi.waitFor( async () => { const updatedResponse = await getJsonResponse(); diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/.env b/packages/vite-plugin-cloudflare/playground/dot-env/.env new file mode 100644 index 000000000000..fd451e9d186b --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/.env @@ -0,0 +1,4 @@ +ENV_NAME = "" +MY_DEV_VAR_A = "my .env variable A" +MY_DEV_VAR_B = "my .env variable B" +MY_DEV_VAR_C = "my .env variable C" diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/.env.staging b/packages/vite-plugin-cloudflare/playground/dot-env/.env.staging new file mode 100644 index 000000000000..fc6f6c87db8d --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/.env.staging @@ -0,0 +1,3 @@ +ENV_NAME = "staging" +MY_DEV_VAR_A = "my .env staging variable A" +MY_DEV_VAR_B = "my .env staging variable B" diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/.env.with-specified-env b/packages/vite-plugin-cloudflare/playground/dot-env/.env.with-specified-env new file mode 100644 index 000000000000..69498a438586 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/.env.with-specified-env @@ -0,0 +1 @@ +CLOUDFLARE_ENV=staging diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/.gitignore b/packages/vite-plugin-cloudflare/playground/dot-env/.gitignore new file mode 100644 index 000000000000..cde945449318 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/.gitignore @@ -0,0 +1 @@ +!.env* diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/dot-env-loading.spec.ts b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/dot-env-loading.spec.ts new file mode 100644 index 000000000000..8f4bbb3f2180 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/dot-env-loading.spec.ts @@ -0,0 +1,39 @@ +import fs from "node:fs"; +import { describe, expect, test } from "vitest"; +import { getJsonResponse, isBuild, testDir } from "../../__test-utils__"; + +const expectedVars = { + MY_DEV_VAR_A: "my .env variable A", + MY_DEV_VAR_B: "my .env variable B", + MY_DEV_VAR_C: "my .env variable C", +}; + +test("reading variables from a standard .env file", async () => { + expect(await getJsonResponse()).toEqual({ + "variables loaded from .env": expectedVars, + }); +}); + +describe.runIf(isBuild)("build output files", () => { + test("the .dev.vars file has been created in the build directory", async () => { + const distDevVarsPath = `${testDir}/dist/worker/.dev.vars`; + const distDevVarsExists = fs.existsSync(distDevVarsPath); + expect(distDevVarsExists).toBe(true); + + const distDevVarsContent = fs.readFileSync(distDevVarsPath, "utf-8"); + expect(distDevVarsContent).toMatchInlineSnapshot(` + "ENV_NAME = "" + MY_DEV_VAR_A = "my .env variable A" + MY_DEV_VAR_B = "my .env variable B" + MY_DEV_VAR_C = "my .env variable C" + " + `); + }); + + test("secrets from .env haven't been inlined in the js output file", async () => { + const distIndexPath = `${testDir}/dist/worker/index.js`; + + const distIndexContent = fs.readFileSync(distIndexPath, "utf-8"); + expect(distIndexContent).not.toContain("my .env variable"); + }); +}); diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts new file mode 100644 index 000000000000..ee295ce766c9 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts @@ -0,0 +1,38 @@ +import * as path from "node:path"; +import { expect, test, vi } from "vitest"; +import { getJsonResponse, isBuild, mockFileChange } from "../../__test-utils__"; + +test.runIf(!isBuild)( + "successfully updates when a var is updated in a .env file", + async () => { + const originalResponseContent = { + "variables loaded from .env": { + MY_DEV_VAR_A: "my .env variable A", + MY_DEV_VAR_B: "my .env variable B", + MY_DEV_VAR_C: "my .env variable C", // Note that unlike .dev.vars, we merge .env files + }, + }; + const originalResponse = await getJsonResponse(); + expect(originalResponse).toEqual( + expect.objectContaining(originalResponseContent) + ); + + mockFileChange(path.join(__dirname, "../.env"), (content) => + content.replace(/my \.env/g, "my .env UPDATED") + ); + + await vi.waitFor( + async () => { + const updatedResponse = await getJsonResponse(); + expect(updatedResponse).toEqual({ + "variables loaded from .env": { + MY_DEV_VAR_A: "my .env UPDATED variable A", + MY_DEV_VAR_B: "my .env UPDATED variable B", + MY_DEV_VAR_C: "my .env UPDATED variable C", // Note that unlike .dev.vars, we merge .env files + }, + }); + }, + { timeout: 5000 } + ); + } +); diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/dot-env-loading.spec.ts b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/dot-env-loading.spec.ts new file mode 100644 index 000000000000..a1407ad8a804 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/dot-env-loading.spec.ts @@ -0,0 +1,36 @@ +import fs from "node:fs"; +import { describe, expect, test } from "vitest"; +import { getJsonResponse, isBuild, testDir } from "../../../__test-utils__"; + +test("reading variables from a staging .env file", async () => { + expect(await getJsonResponse()).toEqual({ + "variables loaded from .env and .env.staging": { + MY_DEV_VAR_A: "my .env staging variable A", + MY_DEV_VAR_B: "my .env staging variable B", + MY_DEV_VAR_C: "my .env variable C", // Note that unlike .dev.vars, we merge .env files + }, + }); +}); +describe.runIf(isBuild)("build output files", () => { + test("the .dev.vars file has been created in the build directory", async () => { + const distDevVarsPath = `${testDir}/dist/worker/.dev.vars`; + const distDevVarsExists = fs.existsSync(distDevVarsPath); + expect(distDevVarsExists).toBe(true); + + const distDevVarsContent = fs.readFileSync(distDevVarsPath, "utf-8"); + expect(distDevVarsContent).toMatchInlineSnapshot(` + "ENV_NAME = "staging" + MY_DEV_VAR_A = "my .env staging variable A" + MY_DEV_VAR_B = "my .env staging variable B" + MY_DEV_VAR_C = "my .env variable C" + " + `); + }); + + test("secrets from .env haven't been inlined in the js output file", async () => { + const distIndexPath = `${testDir}/dist/worker/index.js`; + + const distIndexContent = fs.readFileSync(distIndexPath, "utf-8"); + expect(distIndexContent).not.toContain("my .env"); + }); +}); diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/vars-changes.spec.ts b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/vars-changes.spec.ts new file mode 100644 index 000000000000..db08078036da --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/vars-changes.spec.ts @@ -0,0 +1,43 @@ +import * as path from "node:path"; +import { expect, test, vi } from "vitest"; +import { + getJsonResponse, + isBuild, + mockFileChange, +} from "../../../__test-utils__"; + +test.runIf(!isBuild)( + "successfully updates when a var is updated in a .env.staging file", + async () => { + const originalResponseContent = { + "variables loaded from .env and .env.staging": { + MY_DEV_VAR_A: "my .env staging variable A", + MY_DEV_VAR_B: "my .env staging variable B", + MY_DEV_VAR_C: "my .env variable C", // Note that unlike .dev.vars, we merge .env files + }, + }; + const originalResponse = await getJsonResponse(); + expect(originalResponse).toEqual(originalResponseContent); + + mockFileChange(path.join(__dirname, "../../.env"), (content) => + content.replace(/my \.env/g, "my .env UPDATED") + ); + mockFileChange(path.join(__dirname, "../../.env.staging"), (content) => + content.replace(/my \.env staging/g, "my .env UPDATED staging") + ); + + await vi.waitFor( + async () => { + const updatedResponse = await getJsonResponse(); + expect(updatedResponse).toEqual({ + "variables loaded from .env and .env.staging": { + MY_DEV_VAR_A: "my .env UPDATED staging variable A", + MY_DEV_VAR_B: "my .env UPDATED staging variable B", + MY_DEV_VAR_C: "my .env UPDATED variable C", // Note that unlike .dev.vars, we merge .env files + }, + }); + }, + { timeout: 5000 } + ); + } +); diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/package.json b/packages/vite-plugin-cloudflare/playground/dot-env/package.json new file mode 100644 index 000000000000..06bb8385c0d4 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/package.json @@ -0,0 +1,19 @@ +{ + "name": "@playground/dot-env", + "private": true, + "type": "module", + "scripts": { + "build": "vite build --app", + "check:types": "tsc --build", + "dev": "vite dev", + "preview": "vite preview" + }, + "devDependencies": { + "@cloudflare/vite-plugin": "workspace:*", + "@cloudflare/workers-tsconfig": "workspace:*", + "@cloudflare/workers-types": "^4.20250711.0", + "typescript": "catalog:default", + "vite": "catalog:vite-plugin", + "wrangler": "workspace:*" + } +} diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/src/index.ts b/packages/vite-plugin-cloudflare/playground/dot-env/src/index.ts new file mode 100644 index 000000000000..eff1f85a5cbd --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/src/index.ts @@ -0,0 +1,9 @@ +export default { + async fetch(_req, env) { + const { ENV_NAME, ...variables } = env; + const extra = ENV_NAME ? ` and .env.${ENV_NAME}` : ""; + return Response.json({ + [`variables loaded from .env${extra}`]: variables, + }); + }, +} satisfies ExportedHandler; diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.json b/packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.json new file mode 100644 index 000000000000..b52af703bdc2 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.node.json" }, + { "path": "./tsconfig.worker.json" } + ] +} diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.node.json b/packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.node.json new file mode 100644 index 000000000000..57214ece0e56 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.node.json @@ -0,0 +1,8 @@ +{ + "extends": ["@cloudflare/workers-tsconfig/base.json"], + "include": [ + "vite.config.ts", + "vite.config.with-specified-env.ts", + "__tests__" + ] +} diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.worker.json b/packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.worker.json new file mode 100644 index 000000000000..c22c55c577c8 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/tsconfig.worker.json @@ -0,0 +1,4 @@ +{ + "extends": ["@cloudflare/workers-tsconfig/worker.json"], + "include": ["src", "worker-configuration.d.ts"] +} diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/turbo.json b/packages/vite-plugin-cloudflare/playground/dot-env/turbo.json new file mode 100644 index 000000000000..6556dcf3e5e5 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://turbo.build/schema.json", + "extends": ["//"], + "tasks": { + "build": { + "outputs": ["dist/**"] + } + } +} diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/vite.config.ts b/packages/vite-plugin-cloudflare/playground/dot-env/vite.config.ts new file mode 100644 index 000000000000..9c6b158cb564 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/vite.config.ts @@ -0,0 +1,6 @@ +import { cloudflare } from "@cloudflare/vite-plugin"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [cloudflare({ inspectorPort: false, persistState: false })], +}); diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/vite.config.with-specified-env.ts b/packages/vite-plugin-cloudflare/playground/dot-env/vite.config.with-specified-env.ts new file mode 100644 index 000000000000..d998083274ad --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/vite.config.with-specified-env.ts @@ -0,0 +1,7 @@ +import { cloudflare } from "@cloudflare/vite-plugin"; +import { defineConfig } from "vite"; + +export default defineConfig({ + mode: "with-specified-env", + plugins: [cloudflare({ inspectorPort: false, persistState: false })], +}); diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/worker-configuration.d.ts b/packages/vite-plugin-cloudflare/playground/dot-env/worker-configuration.d.ts new file mode 100644 index 000000000000..913b9d5e9e99 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/worker-configuration.d.ts @@ -0,0 +1,8 @@ +// Generated by Wrangler by running `wrangler types` + +interface Env { + ENV_NAME: string; + MY_DEV_VAR_A: string; + MY_DEV_VAR_B: string; + MY_DEV_VAR_C: string; +} diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/wrangler.jsonc b/packages/vite-plugin-cloudflare/playground/dot-env/wrangler.jsonc new file mode 100644 index 000000000000..22c5bdd32389 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/dot-env/wrangler.jsonc @@ -0,0 +1,8 @@ +{ + "name": "worker", + "main": "./src/index.ts", + "compatibility_date": "2024-12-30", + "env": { + "staging": {}, + }, +} diff --git a/packages/vite-plugin-cloudflare/src/dev-vars.ts b/packages/vite-plugin-cloudflare/src/dev-vars.ts index dcb3237ee5ce..0857205ecfa6 100644 --- a/packages/vite-plugin-cloudflare/src/dev-vars.ts +++ b/packages/vite-plugin-cloudflare/src/dev-vars.ts @@ -1,58 +1,56 @@ -import * as fs from "node:fs"; import * as path from "node:path"; +import { unstable_getVarsForDev } from "wrangler"; import type { AssetsOnlyResolvedConfig, WorkersResolvedConfig, } from "./plugin-config"; /** - * Gets the content of the `.dev.vars` target file + * Gets any variables with which to augment the Worker config in preview mode. * - * Note: This resolves the .dev.vars file path following the same logic - * as `loadDotEnv` in `/packages/wrangler/src/config/index.ts` - * the two need to be kept in sync + * Calls `unstable_getVarsForDev` with the current Cloudflare environment to get local dev variables from the `.dev.vars` and `.env` files. */ -export function getDotDevDotVarsContent( - configPath: string, +export function getLocalDevVars( + configPath: string | undefined, cloudflareEnv: string | undefined -) { - const configDir = path.dirname(configPath); - - const defaultDotDevDotVarsPath = `${configDir}/.dev.vars`; - const inputDotDevDotVarsPath = `${defaultDotDevDotVarsPath}${cloudflareEnv ? `.${cloudflareEnv}` : ""}`; - - const targetPath = fs.existsSync(inputDotDevDotVarsPath) - ? inputDotDevDotVarsPath - : fs.existsSync(defaultDotDevDotVarsPath) - ? defaultDotDevDotVarsPath - : null; - - if (targetPath) { - const dotDevDotVarsContent = fs.readFileSync(targetPath); +): string | undefined { + const dotDevDotVars = unstable_getVarsForDev( + configPath, + undefined, // We don't currently support setting a custom path to the `.env` files. + {}, // Don't pass actual vars since these will be loaded from the wrangler.json. + cloudflareEnv + ); + const dotDevDotVarsEntries = Array.from(Object.entries(dotDevDotVars)); + if (dotDevDotVarsEntries.length > 0) { + const dotDevDotVarsContent = dotDevDotVarsEntries + .map(([key, value]) => { + return `${key} = "${value?.toString().replaceAll(`"`, `\\"`)}"\n`; + }) + .join(""); return dotDevDotVarsContent; } - - return null; } /** - * Returns `true` if the `changedFile` matches a `.dev.vars` file. + * Returns `true` if the `changedFile` matches a `.dev.vars` or `.env` file. */ -export function hasDotDevDotVarsFileChanged( - resolvedPluginConfig: AssetsOnlyResolvedConfig | WorkersResolvedConfig, +export function hasLocalDevVarsFileChanged( + { + configPaths, + cloudflareEnv, + }: AssetsOnlyResolvedConfig | WorkersResolvedConfig, changedFilePath: string ) { - return [...resolvedPluginConfig.configPaths].some((configPath) => { - const dotDevDotVars = path.join(path.dirname(configPath), ".dev.vars"); - if (dotDevDotVars === changedFilePath) { - return true; - } - - if (resolvedPluginConfig.cloudflareEnv) { - const dotDevDotVarsForEnv = `${dotDevDotVars}.${resolvedPluginConfig.cloudflareEnv}`; - return dotDevDotVarsForEnv === changedFilePath; - } - - return false; + return [...configPaths].some((configPath) => { + const configDir = path.dirname(configPath); + return [ + ".dev.vars", + ".env", + ...(cloudflareEnv + ? [`.dev.vars.${cloudflareEnv}`, `.env.${cloudflareEnv}`] + : []), + ].some( + (localDevFile) => changedFilePath === path.join(configDir, localDevFile) + ); }); } diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index 384aff6cf505..9a5aefb8aa14 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -40,10 +40,7 @@ import { getResolvedInspectorPort, } from "./debugging"; import { writeDeployConfig } from "./deploy-config"; -import { - getDotDevDotVarsContent, - hasDotDevDotVarsFileChanged, -} from "./dev-vars"; +import { getLocalDevVars, hasLocalDevVarsFileChanged } from "./dev-vars"; import { getDevMiniflareOptions, getEntryWorkerConfig, @@ -274,17 +271,16 @@ if (import.meta.hot) { config = workerConfig; if (workerConfig.configPath) { - const dotDevDotVarsContent = getDotDevDotVarsContent( + const localDevVars = getLocalDevVars( workerConfig.configPath, resolvedPluginConfig.cloudflareEnv ); - // Save a .dev.vars file to the worker's build output directory - // when it exists so that it will be then detected by `vite preview` - if (dotDevDotVarsContent) { + // Save a .dev.vars file to the worker's build output directory if there are local dev vars, so that it will be then detected by `vite preview`. + if (localDevVars) { this.emitFile({ type: "asset", fileName: ".dev.vars", - source: dotDevDotVarsContent, + source: localDevVars, }); } } @@ -344,7 +340,7 @@ if (import.meta.hot) { if ( resolvedPluginConfig.configPaths.has(changedFilePath) || - hasDotDevDotVarsFileChanged(resolvedPluginConfig, changedFilePath) || + hasLocalDevVarsFileChanged(resolvedPluginConfig, changedFilePath) || hasAssetsConfigChanged( resolvedPluginConfig, resolvedViteConfig, diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 77bdaa86d6f3..4dd9a92b0fe3 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -32,6 +32,7 @@ import type { WorkerOptions, } from "miniflare"; +export { getVarsForDev as unstable_getVarsForDev } from "../../../dev/dev-vars"; export { readConfig as unstable_readConfig }; export type { Config as Unstable_Config, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1e3707aec20a..0819e5542ce8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2351,6 +2351,27 @@ importers: specifier: workspace:* version: link:../../../wrangler + packages/vite-plugin-cloudflare/playground/dot-env: + devDependencies: + '@cloudflare/vite-plugin': + specifier: workspace:* + version: link:../.. + '@cloudflare/workers-tsconfig': + specifier: workspace:* + version: link:../../../workers-tsconfig + '@cloudflare/workers-types': + specifier: ^4.20250711.0 + version: 4.20250712.0 + typescript: + specifier: catalog:default + version: 5.8.2 + vite: + specifier: catalog:vite-plugin + version: 7.0.0(@types/node@20.17.32)(jiti@2.4.2)(lightningcss@1.29.2) + wrangler: + specifier: workspace:* + version: link:../../../wrangler + packages/vite-plugin-cloudflare/playground/durable-objects: devDependencies: '@cloudflare/vite-plugin': @@ -18638,7 +18659,7 @@ snapshots: dotenv-cli@7.3.0: dependencies: cross-spawn: 7.0.6 - dotenv: 16.3.1 + dotenv: 16.6.1 dotenv-expand: 10.0.0 minimist: 1.2.6 From 6bb75c59be0605353aa0f11507f52b479822d33c Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Tue, 15 Jul 2025 13:58:48 +0100 Subject: [PATCH 04/42] add various e2e and fixture tests for dotenv support - `wrangler types` - `wrangler pages dev` - `wrangler dev` - nodejs app using `process.env` --- fixtures/nodejs-hybrid-app/.env | 1 + fixtures/nodejs-hybrid-app/.gitignore | 1 + fixtures/nodejs-hybrid-app/src/index.ts | 4 + .../nodejs-hybrid-app/tests/index.test.ts | 22 ++++ fixtures/nodejs-hybrid-app/wrangler.jsonc | 5 +- fixtures/pages-workerjs-app/.env | 1 + fixtures/pages-workerjs-app/.gitignore | 1 + fixtures/pages-workerjs-app/package.json | 2 +- .../pages-workerjs-app/tests/index.test.ts | 31 ++++- .../workerjs-test/_worker.js | 8 +- fixtures/worker-app/.env | 1 + fixtures/worker-app/.gitignore | 1 + fixtures/worker-app/src/index.js | 1 + ...-vars.test.ts => build-conditions.test.ts} | 0 fixtures/worker-app/tests/index.test.ts | 6 + .../vite-plugin-cloudflare/e2e/basic.test.ts | 120 ++++++++++++++++-- .../e2e/fixtures/basic/api/index.ts | 4 + .../e2e/fixtures/basic/tsconfig.worker.json | 2 +- .../e2e/fixtures/basic/wrangler.jsonc | 3 + packages/wrangler/e2e/types.test.ts | 29 +++++ 20 files changed, 223 insertions(+), 20 deletions(-) create mode 100644 fixtures/nodejs-hybrid-app/.env create mode 100644 fixtures/nodejs-hybrid-app/.gitignore create mode 100644 fixtures/pages-workerjs-app/.env create mode 100644 fixtures/pages-workerjs-app/.gitignore create mode 100644 fixtures/worker-app/.env rename fixtures/worker-app/tests/{env-vars.test.ts => build-conditions.test.ts} (100%) diff --git a/fixtures/nodejs-hybrid-app/.env b/fixtures/nodejs-hybrid-app/.env new file mode 100644 index 000000000000..d81f8ff0f9a1 --- /dev/null +++ b/fixtures/nodejs-hybrid-app/.env @@ -0,0 +1 @@ +DEV_VAR_FROM_DOT_ENV="dev-var-from-dot-env" \ No newline at end of file diff --git a/fixtures/nodejs-hybrid-app/.gitignore b/fixtures/nodejs-hybrid-app/.gitignore new file mode 100644 index 000000000000..1e18f275e97c --- /dev/null +++ b/fixtures/nodejs-hybrid-app/.gitignore @@ -0,0 +1 @@ +!.env \ No newline at end of file diff --git a/fixtures/nodejs-hybrid-app/src/index.ts b/fixtures/nodejs-hybrid-app/src/index.ts index e8be3d3d4275..2bb97e3eef38 100644 --- a/fixtures/nodejs-hybrid-app/src/index.ts +++ b/fixtures/nodejs-hybrid-app/src/index.ts @@ -22,6 +22,10 @@ export default { return testGetRandomValues(); case "/test-process": return testProcessBehavior(); + case "/env": + return Response.json(env); + case "/process-env": + return Response.json(process.env); case "/query": return testPostgresLibrary(env, ctx); case "/test-x509-certificate": diff --git a/fixtures/nodejs-hybrid-app/tests/index.test.ts b/fixtures/nodejs-hybrid-app/tests/index.test.ts index 85a9ac56cdb8..d52c83ddff27 100644 --- a/fixtures/nodejs-hybrid-app/tests/index.test.ts +++ b/fixtures/nodejs-hybrid-app/tests/index.test.ts @@ -88,4 +88,26 @@ describe("nodejs compat", () => { const response = await fetch(`http://${ip}:${port}/test-http`); await expect(response.text()).resolves.toBe("OK"); }); + + test("process.env contains vars", async ({ expect }) => { + const { ip, port } = wrangler; + const response = await fetch(`http://${ip}:${port}/process-env`); + await expect(response.json()).resolves.toEqual( + expect.objectContaining({ + DB_HOSTNAME: "hh-pgsql-public.ebi.ac.uk", + DEV_VAR_FROM_DOT_ENV: "dev-var-from-dot-env", + }) + ); + }); + + test("env contains vars", async ({ expect }) => { + const { ip, port } = wrangler; + const response = await fetch(`http://${ip}:${port}/env`); + await expect(response.json()).resolves.toEqual( + expect.objectContaining({ + DB_HOSTNAME: "hh-pgsql-public.ebi.ac.uk", + DEV_VAR_FROM_DOT_ENV: "dev-var-from-dot-env", + }) + ); + }); }); diff --git a/fixtures/nodejs-hybrid-app/wrangler.jsonc b/fixtures/nodejs-hybrid-app/wrangler.jsonc index ac6d7d7b2e87..940dc869f77b 100644 --- a/fixtures/nodejs-hybrid-app/wrangler.jsonc +++ b/fixtures/nodejs-hybrid-app/wrangler.jsonc @@ -1,8 +1,9 @@ { "name": "nodejs-hybrid-app", "main": "src/index.ts", - // Setting compat date to 2024/09/23 means we don't need to use `nodejs_compat_v2` - "compatibility_date": "2024-09-23", + // Setting compat date after 2024/09/23 means we don't need to use `nodejs_compat_v2` + // Setting compat date after 2025/04/01 means we don't need to use `nodejs_compat_populate_process_env` + "compatibility_date": "2025-07-01", "compatibility_flags": ["nodejs_compat"], /* These DB connection values are to a public database containing information about diff --git a/fixtures/pages-workerjs-app/.env b/fixtures/pages-workerjs-app/.env new file mode 100644 index 000000000000..1566bb1d76a7 --- /dev/null +++ b/fixtures/pages-workerjs-app/.env @@ -0,0 +1 @@ +FOO=bar \ No newline at end of file diff --git a/fixtures/pages-workerjs-app/.gitignore b/fixtures/pages-workerjs-app/.gitignore new file mode 100644 index 000000000000..1e18f275e97c --- /dev/null +++ b/fixtures/pages-workerjs-app/.gitignore @@ -0,0 +1 @@ +!.env \ No newline at end of file diff --git a/fixtures/pages-workerjs-app/package.json b/fixtures/pages-workerjs-app/package.json index b9dcbdcbbb7a..ff4c20e311cf 100644 --- a/fixtures/pages-workerjs-app/package.json +++ b/fixtures/pages-workerjs-app/package.json @@ -4,7 +4,7 @@ "sideEffects": false, "scripts": { "check:type": "tsc", - "dev": "wrangler pages dev ./workerjs-test --port 8792", + "dev": "wrangler pages dev ./workerjs-test --port 8792 --compatibility-date=2025-07-15", "test:ci": "vitest run", "test:watch": "vitest", "type:tests": "tsc -p ./tests/tsconfig.json" diff --git a/fixtures/pages-workerjs-app/tests/index.test.ts b/fixtures/pages-workerjs-app/tests/index.test.ts index 7222233764f0..61d9d87582e5 100644 --- a/fixtures/pages-workerjs-app/tests/index.test.ts +++ b/fixtures/pages-workerjs-app/tests/index.test.ts @@ -35,7 +35,12 @@ describe("Pages _worker.js", () => { const { ip, port, stop } = await runWranglerPagesDev( resolve(__dirname, ".."), "./workerjs-test", - ["--no-bundle=false", "--port=0", "--inspector-port=0"] + [ + "--no-bundle=false", + "--port=0", + "--inspector-port=0", + "--compatibility-date=2025-07-15", + ] ); try { await expect( @@ -52,7 +57,12 @@ describe("Pages _worker.js", () => { const { ip, port, stop } = await runWranglerPagesDev( resolve(__dirname, ".."), "./workerjs-test", - ["--bundle", "--port=0", "--inspector-port=0"] + [ + "--bundle", + "--port=0", + "--inspector-port=0", + "--compatibility-date=2025-07-15", + ] ); try { await expect( @@ -71,6 +81,7 @@ describe("Pages _worker.js", () => { await runWranglerPagesDev(resolve(__dirname, ".."), "./workerjs-test", [ "--port=0", "--inspector-port=0", + "--compatibility-date=2025-07-15", ]); vi.waitFor( () => { @@ -157,6 +168,22 @@ describe("Pages _worker.js", () => { } }); + // Serendipitously, this .env reading also works for `wrangler pages dev`. + it("should read local dev vars from the .env file", async ({ expect }) => { + const { ip, port, stop } = await runWranglerPagesDev( + resolve(__dirname, ".."), + "./workerjs-test", + ["--port=0", "--inspector-port=0", "--compatibility-date=2025-07-15"] + ); + try { + const response = await fetch(`http://${ip}:${port}/env`); + const env = (await response.json()) as { FOO: string }; + expect(env.FOO).toBe("bar"); + } finally { + await stop(); + } + }); + async function tryRename( basePath: string, from: string, diff --git a/fixtures/pages-workerjs-app/workerjs-test/_worker.js b/fixtures/pages-workerjs-app/workerjs-test/_worker.js index 7e6b44790b7b..c5174509965c 100644 --- a/fixtures/pages-workerjs-app/workerjs-test/_worker.js +++ b/fixtures/pages-workerjs-app/workerjs-test/_worker.js @@ -1,7 +1,11 @@ import text from "./other-script"; export default { - async fetch() { - return new Response(text); + async fetch(request, env) { + if (request.url.endsWith("/env")) { + return Response.json(env); + } else { + return new Response(text); + } }, }; diff --git a/fixtures/worker-app/.env b/fixtures/worker-app/.env new file mode 100644 index 000000000000..1566bb1d76a7 --- /dev/null +++ b/fixtures/worker-app/.env @@ -0,0 +1 @@ +FOO=bar \ No newline at end of file diff --git a/fixtures/worker-app/.gitignore b/fixtures/worker-app/.gitignore index 1521c8b7652b..b67a5dd0610b 100644 --- a/fixtures/worker-app/.gitignore +++ b/fixtures/worker-app/.gitignore @@ -1 +1,2 @@ dist +!.env \ No newline at end of file diff --git a/fixtures/worker-app/src/index.js b/fixtures/worker-app/src/index.js index f8d72b34abed..f97b90b1efe6 100644 --- a/fixtures/worker-app/src/index.js +++ b/fixtures/worker-app/src/index.js @@ -25,6 +25,7 @@ export default { const { pathname, origin, hostname, host } = new URL(request.url); if (pathname.startsWith("/fav")) return new Response("Not found", { status: 404 }); + if (pathname === "/env") return Response.json(env.FOO); if (pathname === "/version_metadata") return Response.json(env.METADATA); if (pathname === "/random") return new Response(hexEncode(randomBytes(8))); if (pathname === "/error") throw new Error("Oops!"); diff --git a/fixtures/worker-app/tests/env-vars.test.ts b/fixtures/worker-app/tests/build-conditions.test.ts similarity index 100% rename from fixtures/worker-app/tests/env-vars.test.ts rename to fixtures/worker-app/tests/build-conditions.test.ts diff --git a/fixtures/worker-app/tests/index.test.ts b/fixtures/worker-app/tests/index.test.ts index f4d78ea09c0a..f3bd1b553b4d 100644 --- a/fixtures/worker-app/tests/index.test.ts +++ b/fixtures/worker-app/tests/index.test.ts @@ -203,4 +203,10 @@ describe("'wrangler dev' correctly renders pages", () => { ] `); }); + + it("reads local dev vars from the .env file", async ({ expect }) => { + const response = await fetch(`http://${ip}:${port}/env`); + const env = await response.text(); + expect(env).toBe(`"bar"`); + }); }); diff --git a/packages/vite-plugin-cloudflare/e2e/basic.test.ts b/packages/vite-plugin-cloudflare/e2e/basic.test.ts index 1fb6ede017cf..817e8981045a 100644 --- a/packages/vite-plugin-cloudflare/e2e/basic.test.ts +++ b/packages/vite-plugin-cloudflare/e2e/basic.test.ts @@ -1,8 +1,8 @@ +import { rm, writeFile } from "node:fs/promises"; import { describe, test } from "vitest"; import { fetchJson, runLongLived, seed, waitForReady } from "./helpers.js"; -const isWindows = process.platform === "win32"; -const packageManagers = ["pnpm", , "npm", "yarn"] as const; +const packageManagers = ["pnpm", "npm", "yarn"] as const; const commands = ["dev", "buildAndPreview"] as const; describe("basic e2e tests", () => { @@ -10,16 +10,112 @@ describe("basic e2e tests", () => { const projectPath = seed("basic", pm); describe.each(commands)('with "%s" command', (command) => { - describe("node compatibility", () => { - test.skipIf(command === "buildAndPreview")( - "can serve a Worker request", - async ({ expect }) => { - const proc = await runLongLived(pm, command, projectPath); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/api/")).toEqual({ - name: "Cloudflare", - }); - } + test("can serve a Worker that uses a Node.js API (crypto)", async ({ + expect, + }) => { + const proc = await runLongLived(pm, command, projectPath); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/api/")).toEqual({ + name: "Cloudflare", + }); + }); + + describe("environment variables", () => { + test("can read vars from wrangler configuration and .env", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dev-1\nSECRET_B=dev-2" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + }); + const proc = await runLongLived(pm, command, projectPath); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toEqual( + expect.objectContaining({ + SECRET_A: "dev-1", + SECRET_B: "dev-2", + VAR_1: "var-1", + }) + ); + }); + + test("can merge vars from wrangler configuration, .env, and .env.local", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dev-1\nSECRET_B=dev-2" + ); + await writeFile(projectPath + "/.env.local", "SECRET_A=local-dev-1"); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + await rm(projectPath + "/.env.local"); + }); + const proc = await runLongLived(pm, command, projectPath); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toEqual( + expect.objectContaining({ + SECRET_A: "local-dev-1", + SECRET_B: "dev-2", + VAR_1: "var-1", + }) + ); + }); + }); + + test("can merge vars from wrangler configuration, .env, and .env.local, and environment specific files", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dev-1\nSECRET_B=dev-2" + ); + await writeFile(projectPath + "/.env.local", "SECRET_A=local-dev-1"); + await writeFile( + projectPath + "/.env.staging", + "SECRET_B=staging-2\nSECRET_C=staging-3" + ); + await writeFile( + projectPath + "/.env.staging.local", + "SECRET_C=local-staging-3" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + await rm(projectPath + "/.env.local"); + await rm(projectPath + "/.env.staging"); + await rm(projectPath + "/.env.staging.local"); + }); + const proc = await runLongLived(pm, command, projectPath, { + CLOUDFLARE_ENV: "staging", + }); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toEqual( + expect.objectContaining({ + SECRET_A: "local-dev-1", + SECRET_B: "staging-2", + SECRET_C: "local-staging-3", + VAR_1: "var-1", + }) + ); + }); + + test("can read vars from process.env if CLOUDFLARE_INCLUDE_PROCESS_ENV is set", async ({ + expect, + }) => { + const proc = await runLongLived(pm, command, projectPath, { + CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", + }); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toEqual( + expect.objectContaining({ + CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", // this proves we read the process.env + }) ); }); diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/basic/api/index.ts b/packages/vite-plugin-cloudflare/e2e/fixtures/basic/api/index.ts index 285ee3304c1a..d7e420302ad1 100644 --- a/packages/vite-plugin-cloudflare/e2e/fixtures/basic/api/index.ts +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/basic/api/index.ts @@ -17,6 +17,10 @@ export default { }); } + if (url.pathname === "/env/") { + return Response.json(env); + } + if (url.pathname.startsWith("/ai/")) { const messages = [ { diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/basic/tsconfig.worker.json b/packages/vite-plugin-cloudflare/e2e/fixtures/basic/tsconfig.worker.json index a0819b950a6e..2c0ec94c20f0 100644 --- a/packages/vite-plugin-cloudflare/e2e/fixtures/basic/tsconfig.worker.json +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/basic/tsconfig.worker.json @@ -2,7 +2,7 @@ "extends": "./tsconfig.node.json", "compilerOptions": { "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo", - "types": ["@cloudflare/workers-types/2023-07-01", "vite/client"] + "types": ["@cloudflare/workers-types/2023-07-01", "vite/client", "node"] }, "include": ["api"] } diff --git a/packages/vite-plugin-cloudflare/e2e/fixtures/basic/wrangler.jsonc b/packages/vite-plugin-cloudflare/e2e/fixtures/basic/wrangler.jsonc index 41cd5113e133..625d6aab622f 100644 --- a/packages/vite-plugin-cloudflare/e2e/fixtures/basic/wrangler.jsonc +++ b/packages/vite-plugin-cloudflare/e2e/fixtures/basic/wrangler.jsonc @@ -10,4 +10,7 @@ "ai": { "binding": "AI", }, + "vars": { + "VAR_1": "var-1", + }, } diff --git a/packages/wrangler/e2e/types.test.ts b/packages/wrangler/e2e/types.test.ts index 7c0d4582eed6..09e5cb2e3c77 100644 --- a/packages/wrangler/e2e/types.test.ts +++ b/packages/wrangler/e2e/types.test.ts @@ -188,4 +188,33 @@ describe("types", () => { await helper.seed(seed); await worker.readUntil(/❓ Your types might be out of date./); }); + + it("should read .env files for secret env vars", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed(seed); + await helper.seed({ + ".env": dedent` + MY_VAR=secret-value + `, + }); + const output = await helper.run(`wrangler types --include-runtime=false`); + expect(output.stdout).not.toContain("Generating runtime types..."); + const file = readFileSync( + path.join(helper.tmpPath, "./worker-configuration.d.ts"), + "utf8" + ); + expect(file).toMatchInlineSnapshot(` + "/* eslint-disable */ + // Generated by Wrangler by running \`wrangler types --include-runtime=false\` (hash: e5830092ae2a4ea3789f0d1c1fc31ff8) + declare namespace Cloudflare { + interface Env { + BEEP: "BOOP"; + ASDf: "ADSfadsf"; + MY_VAR: string; + } + } + interface Env extends Cloudflare.Env {} + " + `); + }); }); From 914876555106ea161af32d008ebe63b1b239371e Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Tue, 15 Jul 2025 14:30:36 +0100 Subject: [PATCH 05/42] add a changeset --- .changeset/moody-breads-pump.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .changeset/moody-breads-pump.md diff --git a/.changeset/moody-breads-pump.md b/.changeset/moody-breads-pump.md new file mode 100644 index 000000000000..5940d5a56d27 --- /dev/null +++ b/.changeset/moody-breads-pump.md @@ -0,0 +1,19 @@ +--- +"@cloudflare/vite-plugin": minor +"wrangler": minor +--- + +Add support for loading local dev vars from .env files + +If there are no `.dev.vars` or `.dev.vars.` files, when running Wrangler or the Vite plugin in local development mode, +they will now try to load additional local dev vars from `.env`, `.env.local`, `.env.` and `.env..local` files. + +These loaded vars are only for local development and have no effect in production to the vars in a deployed Worker. +Wrangler and Vite will continue to load `.env` files in order to configure themselves as a tool. + +Further details: + +- In `vite build` the local vars will be computed and stored in a `.dev.vars` file next to the compiled Worker code, so that `vite preview` can use them. +- The `wrangler types` command will similarly read the `.env` files (if no `.dev.vars` files) in order to generate the `Env` interface. +- If the `CLOUDFLARE_INCLUDE_PROCESS_ENV` environment variable is `true` then all the environment variables found on `process.env` will be included as local dev vars. +- Wrangler (but not Vite plugin) also now supports the `--env-file=` global CLI option. This affects both loading `.env` to configure Wrangler the tool as well as loading local dev vars. From ffc09222c5475c2d978ba203c670097ef2aa159c Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 18 Jul 2025 14:20:56 +0100 Subject: [PATCH 06/42] fixup! add support to Wrangler for setting the path to the .env files --- packages/wrangler/e2e/dev.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/wrangler/e2e/dev.test.ts b/packages/wrangler/e2e/dev.test.ts index 43596bc96f0e..bd91d2fa8504 100644 --- a/packages/wrangler/e2e/dev.test.ts +++ b/packages/wrangler/e2e/dev.test.ts @@ -2579,7 +2579,7 @@ describe(".env support in local dev", () => { "WRANGLER_ENV_VAR_0": "default-0", "WRANGLER_ENV_VAR_1": "other-env-1", "WRANGLER_ENV_VAR_2": "other-local-2", - "WRANGLER_ENV_VAR_3": "other-local-3", + "WRANGLER_ENV_VAR_3": "other-local-3" }" `); }); From 35c8831c011b53c14e37550b3fb0dd2e9f67460f Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 18 Jul 2025 14:38:20 +0100 Subject: [PATCH 07/42] use `toMatchObject()` in tests --- .../nodejs-hybrid-app/tests/index.test.ts | 6 ++--- .../vite-plugin-cloudflare/e2e/basic.test.ts | 25 +++++++------------ .../dot-env/__tests__/vars-changes.spec.ts | 4 +-- packages/wrangler/src/__tests__/dev.test.ts | 6 ++--- 4 files changed, 14 insertions(+), 27 deletions(-) diff --git a/fixtures/nodejs-hybrid-app/tests/index.test.ts b/fixtures/nodejs-hybrid-app/tests/index.test.ts index d52c83ddff27..1d61ad31c342 100644 --- a/fixtures/nodejs-hybrid-app/tests/index.test.ts +++ b/fixtures/nodejs-hybrid-app/tests/index.test.ts @@ -92,8 +92,7 @@ describe("nodejs compat", () => { test("process.env contains vars", async ({ expect }) => { const { ip, port } = wrangler; const response = await fetch(`http://${ip}:${port}/process-env`); - await expect(response.json()).resolves.toEqual( - expect.objectContaining({ + await expect(response.json()).resolves.toMatchObject({ DB_HOSTNAME: "hh-pgsql-public.ebi.ac.uk", DEV_VAR_FROM_DOT_ENV: "dev-var-from-dot-env", }) @@ -103,8 +102,7 @@ describe("nodejs compat", () => { test("env contains vars", async ({ expect }) => { const { ip, port } = wrangler; const response = await fetch(`http://${ip}:${port}/env`); - await expect(response.json()).resolves.toEqual( - expect.objectContaining({ + await expect(response.json()).resolves.toMatchObject({ DB_HOSTNAME: "hh-pgsql-public.ebi.ac.uk", DEV_VAR_FROM_DOT_ENV: "dev-var-from-dot-env", }) diff --git a/packages/vite-plugin-cloudflare/e2e/basic.test.ts b/packages/vite-plugin-cloudflare/e2e/basic.test.ts index 817e8981045a..cfcad315bd9c 100644 --- a/packages/vite-plugin-cloudflare/e2e/basic.test.ts +++ b/packages/vite-plugin-cloudflare/e2e/basic.test.ts @@ -34,13 +34,11 @@ describe("basic e2e tests", () => { }); const proc = await runLongLived(pm, command, projectPath); const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toEqual( - expect.objectContaining({ + expect(await fetchJson(url + "/env/")).toMatchObject({ SECRET_A: "dev-1", SECRET_B: "dev-2", VAR_1: "var-1", - }) - ); + }); }); test("can merge vars from wrangler configuration, .env, and .env.local", async ({ @@ -58,13 +56,10 @@ describe("basic e2e tests", () => { }); const proc = await runLongLived(pm, command, projectPath); const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toEqual( - expect.objectContaining({ + expect(await fetchJson(url + "/env/")).toMatchObject({ SECRET_A: "local-dev-1", SECRET_B: "dev-2", VAR_1: "var-1", - }) - ); }); }); @@ -95,14 +90,12 @@ describe("basic e2e tests", () => { CLOUDFLARE_ENV: "staging", }); const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toEqual( - expect.objectContaining({ + expect(await fetchJson(url + "/env/")).toMatchObject({ SECRET_A: "local-dev-1", SECRET_B: "staging-2", SECRET_C: "local-staging-3", VAR_1: "var-1", - }) - ); + }); }); test("can read vars from process.env if CLOUDFLARE_INCLUDE_PROCESS_ENV is set", async ({ @@ -112,11 +105,11 @@ describe("basic e2e tests", () => { CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", }); const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toEqual( - expect.objectContaining({ + expect(await fetchJson(url + "/env/")).toMatchObject({ CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", // this proves we read the process.env - }) - ); + }); + }); + }); }); // This test checks that wrapped bindings which rely on additional workers with an authed connection to the CF API work diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts index ee295ce766c9..5cde8dc04573 100644 --- a/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts @@ -13,9 +13,7 @@ test.runIf(!isBuild)( }, }; const originalResponse = await getJsonResponse(); - expect(originalResponse).toEqual( - expect.objectContaining(originalResponseContent) - ); + expect(originalResponse).toMatchObject(originalResponseContent); mockFileChange(path.join(__dirname, "../.env"), (content) => content.replace(/my \.env/g, "my .env UPDATED") diff --git a/packages/wrangler/src/__tests__/dev.test.ts b/packages/wrangler/src/__tests__/dev.test.ts index ea90fa9aea1a..57ee126f9523 100644 --- a/packages/wrangler/src/__tests__/dev.test.ts +++ b/packages/wrangler/src/__tests__/dev.test.ts @@ -89,8 +89,7 @@ async function expectedHostAndZone( configPath: config.config, }); - expect(ctx).toEqual( - expect.objectContaining({ + expect(ctx).toMatchObject({ workerContext: { host, zone, @@ -112,8 +111,7 @@ async function expectedHostAndZone( } }), }, - }) - ); + }); return config; } From 76eee906ff848908154e7de870a356973b5006c4 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 18 Jul 2025 14:42:31 +0100 Subject: [PATCH 08/42] add support for CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV to opt-out of .env file loading --- .changeset/moody-breads-pump.md | 1 + .../vite-plugin-cloudflare/e2e/basic.test.ts | 169 +++++++++++------- packages/wrangler/e2e/dev.test.ts | 26 ++- packages/wrangler/src/__tests__/dev.test.ts | 68 ++++--- packages/wrangler/src/dev/dev-vars.ts | 9 +- .../src/environment-variables/factory.ts | 1 + .../environment-variables/misc-variables.ts | 12 +- 7 files changed, 201 insertions(+), 85 deletions(-) diff --git a/.changeset/moody-breads-pump.md b/.changeset/moody-breads-pump.md index 5940d5a56d27..8f0695f03472 100644 --- a/.changeset/moody-breads-pump.md +++ b/.changeset/moody-breads-pump.md @@ -15,5 +15,6 @@ Further details: - In `vite build` the local vars will be computed and stored in a `.dev.vars` file next to the compiled Worker code, so that `vite preview` can use them. - The `wrangler types` command will similarly read the `.env` files (if no `.dev.vars` files) in order to generate the `Env` interface. +- If the `CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV` environment variable is `false` then local dev variables will not be loaded from `.env` files. - If the `CLOUDFLARE_INCLUDE_PROCESS_ENV` environment variable is `true` then all the environment variables found on `process.env` will be included as local dev vars. - Wrangler (but not Vite plugin) also now supports the `--env-file=` global CLI option. This affects both loading `.env` to configure Wrangler the tool as well as loading local dev vars. diff --git a/packages/vite-plugin-cloudflare/e2e/basic.test.ts b/packages/vite-plugin-cloudflare/e2e/basic.test.ts index cfcad315bd9c..8f9894ea14b4 100644 --- a/packages/vite-plugin-cloudflare/e2e/basic.test.ts +++ b/packages/vite-plugin-cloudflare/e2e/basic.test.ts @@ -35,78 +35,127 @@ describe("basic e2e tests", () => { const proc = await runLongLived(pm, command, projectPath); const url = await waitForReady(proc); expect(await fetchJson(url + "/env/")).toMatchObject({ - SECRET_A: "dev-1", - SECRET_B: "dev-2", + SECRET_A: "dev-1", + SECRET_B: "dev-2", + VAR_1: "var-1", + }); + + test("will not load local dev vars from .env if there is a .dev.vars file", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dot-env-1\nSECRET_B=dot-env-2" + ); + await writeFile( + projectPath + "/.dev.vars", + "SECRET_A=dev-dot-vars-1" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + await rm(projectPath + "/.dev.vars"); + }); + const proc = await runLongLived(pm, command, projectPath); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + SECRET_A: "dev-dot-vars-1", VAR_1: "var-1", + }); }); - }); - test("can merge vars from wrangler configuration, .env, and .env.local", async ({ - expect, - onTestFinished, - }) => { - await writeFile( - projectPath + "/.env", - "SECRET_A=dev-1\nSECRET_B=dev-2" - ); - await writeFile(projectPath + "/.env.local", "SECRET_A=local-dev-1"); - onTestFinished(async () => { - await rm(projectPath + "/.env"); - await rm(projectPath + "/.env.local"); + test("will not load local dev vars from .env if CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV is set to false", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dot-env-1\nSECRET_B=dot-env-2" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + }); + const proc = await runLongLived(pm, command, projectPath, { + CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV: "false", + }); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + VAR_1: "var-1", + }); }); - const proc = await runLongLived(pm, command, projectPath); - const url = await waitForReady(proc); + + test("can merge vars from wrangler configuration, .env, and .env.local", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dev-1\nSECRET_B=dev-2" + ); + await writeFile( + projectPath + "/.env.local", + "SECRET_A=local-dev-1" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + await rm(projectPath + "/.env.local"); + }); + const proc = await runLongLived(pm, command, projectPath); + const url = await waitForReady(proc); expect(await fetchJson(url + "/env/")).toMatchObject({ SECRET_A: "local-dev-1", SECRET_B: "dev-2", VAR_1: "var-1", - }); - }); + }); + }); - test("can merge vars from wrangler configuration, .env, and .env.local, and environment specific files", async ({ - expect, - onTestFinished, - }) => { - await writeFile( - projectPath + "/.env", - "SECRET_A=dev-1\nSECRET_B=dev-2" - ); - await writeFile(projectPath + "/.env.local", "SECRET_A=local-dev-1"); - await writeFile( - projectPath + "/.env.staging", - "SECRET_B=staging-2\nSECRET_C=staging-3" - ); - await writeFile( - projectPath + "/.env.staging.local", - "SECRET_C=local-staging-3" - ); - onTestFinished(async () => { - await rm(projectPath + "/.env"); - await rm(projectPath + "/.env.local"); - await rm(projectPath + "/.env.staging"); - await rm(projectPath + "/.env.staging.local"); - }); - const proc = await runLongLived(pm, command, projectPath, { - CLOUDFLARE_ENV: "staging", - }); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - SECRET_A: "local-dev-1", - SECRET_B: "staging-2", - SECRET_C: "local-staging-3", - VAR_1: "var-1", + test("can merge vars from wrangler configuration, .env, and .env.local, and environment specific files", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dev-1\nSECRET_B=dev-2" + ); + await writeFile( + projectPath + "/.env.local", + "SECRET_A=local-dev-1" + ); + await writeFile( + projectPath + "/.env.staging", + "SECRET_B=staging-2\nSECRET_C=staging-3" + ); + await writeFile( + projectPath + "/.env.staging.local", + "SECRET_C=local-staging-3" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + await rm(projectPath + "/.env.local"); + await rm(projectPath + "/.env.staging"); + await rm(projectPath + "/.env.staging.local"); }); - }); + const proc = await runLongLived(pm, command, projectPath, { + CLOUDFLARE_ENV: "staging", + }); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + SECRET_A: "local-dev-1", + SECRET_B: "staging-2", + SECRET_C: "local-staging-3", + VAR_1: "var-1", + }); + }); - test("can read vars from process.env if CLOUDFLARE_INCLUDE_PROCESS_ENV is set", async ({ - expect, - }) => { - const proc = await runLongLived(pm, command, projectPath, { - CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", - }); - const url = await waitForReady(proc); + test("can read vars from process.env if CLOUDFLARE_INCLUDE_PROCESS_ENV is set", async ({ + expect, + }) => { + const proc = await runLongLived(pm, command, projectPath, { + CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", + }); + const url = await waitForReady(proc); expect(await fetchJson(url + "/env/")).toMatchObject({ - CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", // this proves we read the process.env + CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", // this proves we read the process.env }); }); }); diff --git a/packages/wrangler/e2e/dev.test.ts b/packages/wrangler/e2e/dev.test.ts index bd91d2fa8504..a7fe635c809f 100644 --- a/packages/wrangler/e2e/dev.test.ts +++ b/packages/wrangler/e2e/dev.test.ts @@ -2339,7 +2339,7 @@ describe(".env support in local dev", () => { `); }); - it("should not load load environment variables from .env files if there is a .dev.vars file", async () => { + it("should not load local dev variables from .env files if there is a .dev.vars file", async () => { const helper = new WranglerE2ETestHelper(); await helper.seed(seedFiles); await helper.seed({ @@ -2367,6 +2367,30 @@ describe(".env support in local dev", () => { `); }); + it("should not load dev variables from .env files if CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV is set to false", async () => { + const helper = new WranglerE2ETestHelper(); + await helper.seed(seedFiles); + await helper.seed({ + ".env": dedent` + WRANGLER_ENV_VAR_1=env-1 + WRANGLER_ENV_VAR_2=env-2 + `, + }); + + const worker = helper.runLongLived("wrangler dev", { + env: { CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV: "false" }, + }); + const { url } = await worker.waitForReady(); + expect(await (await fetch(url)).text()).toMatchInlineSnapshot(` + "{ + "WRANGLER_ENV_VAR_0": "default-0", + "WRANGLER_ENV_VAR_1": "default-1", + "WRANGLER_ENV_VAR_2": "default-2", + "WRANGLER_ENV_VAR_3": "default-3" + }" + `); + }); + it("should load environment variables from .env.staging if it exists and --env=staging", async () => { const helper = new WranglerE2ETestHelper(); await helper.seed(seedFiles); diff --git a/packages/wrangler/src/__tests__/dev.test.ts b/packages/wrangler/src/__tests__/dev.test.ts index 57ee126f9523..b41373492799 100644 --- a/packages/wrangler/src/__tests__/dev.test.ts +++ b/packages/wrangler/src/__tests__/dev.test.ts @@ -90,27 +90,27 @@ async function expectedHostAndZone( }); expect(ctx).toMatchObject({ - workerContext: { - host, - zone, - routes: config.triggers - ?.filter( - (trigger): trigger is Extract => - trigger.type === "route" - ) - .map((trigger) => { - const { type: _, ...route } = trigger; - if ( - "custom_domain" in route || - "zone_id" in route || - "zone_name" in route - ) { - return route; - } else { - return route.pattern; - } - }), - }, + workerContext: { + host, + zone, + routes: config.triggers + ?.filter( + (trigger): trigger is Extract => + trigger.type === "route" + ) + .map((trigger) => { + const { type: _, ...route } = trigger; + if ( + "custom_domain" in route || + "zone_id" in route || + "zone_name" in route + ) { + return route; + } else { + return route.pattern; + } + }), + }, }); return config; @@ -1663,6 +1663,32 @@ describe.sequential("wrangler dev", () => { `); }); + it("should not load local dev `vars` from `.env` if there is a `.dev.vars` file", async () => { + fs.writeFileSync( + ".dev.vars", + dedent` + __DOT_DEV_DOT_VARS_LOCAL_DEV_VAR_1=dot-dev-var-1 + __DOT_DEV_DOT_VARS_LOCAL_DEV_VAR_2=dot-dev-var-2 + ` + ); + await runWranglerUntilConfig("dev"); + expect(extractUsingVars(std.out)).toMatchInlineSnapshot(` + "Using vars defined in .dev.vars" + `); + expect(extractBindings(std.out)).toMatchInlineSnapshot(` + "env.__DOT_DEV_DOT_VARS_LOCAL_DEV_VAR_1 (\\"(hidden)\\") Environment Variable local + env.__DOT_DEV_DOT_VARS_LOCAL_DEV_VAR_2 (\\"(hidden)\\") Environment Variable local" + `); + }); + + it("should not load local dev `vars` from `.env` if CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV is set to false", async () => { + await runWranglerUntilConfig("dev", { + CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV: "false", + }); + expect(extractUsingVars(std.out)).toMatchInlineSnapshot(`""`); + expect(extractBindings(std.out)).toMatchInlineSnapshot(`""`); + }); + it("should get local dev `vars` from appropriate `.env.` files when --env= is set", async () => { await runWranglerUntilConfig("dev --env custom"); expect(extractUsingVars(std.out)).toMatchInlineSnapshot(` diff --git a/packages/wrangler/src/dev/dev-vars.ts b/packages/wrangler/src/dev/dev-vars.ts index 769ce85bce87..3172feffb28f 100644 --- a/packages/wrangler/src/dev/dev-vars.ts +++ b/packages/wrangler/src/dev/dev-vars.ts @@ -2,7 +2,10 @@ import * as path from "node:path"; import { maybeGetFile } from "@cloudflare/workers-shared"; import dotenv from "dotenv"; import { getDefaultEnvPaths, loadDotEnv } from "../config/dot-env"; -import { getCloudflareIncludeProcessEnvFromEnv } from "../environment-variables/misc-variables"; +import { + getCloudflareIncludeProcessEnvFromEnv, + getCloudflareLoadDevVarsFromDotEnv, +} from "../environment-variables/misc-variables"; import { logger } from "../logger"; import type { Config } from "../config"; @@ -47,7 +50,7 @@ export function getVarsForDev( ...vars, ...loaded.parsed, }; - } else { + } else if (getCloudflareLoadDevVarsFromDotEnv()) { // If no .dev.vars files load vars from those in `envFilePaths` if defined or default .env files in the configuration directory. const resolvedEnvFilePaths = ( envFilePaths ?? getDefaultEnvPaths(".env", env) @@ -60,6 +63,8 @@ export function getVarsForDev( ...vars, ...dotEnvVars, }; + } else { + return vars; } } diff --git a/packages/wrangler/src/environment-variables/factory.ts b/packages/wrangler/src/environment-variables/factory.ts index 741bc6c88738..a74834b927c6 100644 --- a/packages/wrangler/src/environment-variables/factory.ts +++ b/packages/wrangler/src/environment-variables/factory.ts @@ -39,6 +39,7 @@ type VariableNames = // but including here so that all environment variables are documented here: | "WRANGLER_DOCKER_HOST" | "DOCKER_HOST" + | "CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV" | "CLOUDFLARE_INCLUDE_PROCESS_ENV"; type DeprecatedNames = diff --git a/packages/wrangler/src/environment-variables/misc-variables.ts b/packages/wrangler/src/environment-variables/misc-variables.ts index a50cb03dc0e8..3333c52c4d21 100644 --- a/packages/wrangler/src/environment-variables/misc-variables.ts +++ b/packages/wrangler/src/environment-variables/misc-variables.ts @@ -255,7 +255,7 @@ export const getRegistryPath = getEnvironmentVariableFactory({ /** * `WRANGLER_D1_EXTRA_LOCATION_CHOICES` is an internal variable to let D1 team target their testing environments. * - * External accounts cannot access testing envionments, so should not set this variable. + * External accounts cannot access testing environments, so should not set this variable. */ export const getD1ExtraLocationChoices: () => string | undefined = getEnvironmentVariableFactory({ @@ -274,6 +274,16 @@ export const getDockerPath = getEnvironmentVariableFactory({ }, }); +/** +/** + * `CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV` specifies whether to load vars for local dev from `.env` files. + */ +export const getCloudflareLoadDevVarsFromDotEnv = + getBooleanEnvironmentVariableFactory({ + variableName: "CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV", + defaultValue: () => true, + }); + /** * `CLOUDFLARE_INCLUDE_PROCESS_ENV` specifies whether to include the `process.env` in vars loaded from `.env` for local development. */ From 18da8be90f9acfba0932aa9ba8266c60e958d5c9 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 18 Jul 2025 14:52:01 +0100 Subject: [PATCH 09/42] tidy up `envFiles` documentation --- .../src/api/integrations/platform/index.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 4dd9a92b0fe3..348863cd8bb6 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -58,14 +58,18 @@ export type GetPlatformProxyOptions = { */ configPath?: string; /** - * Paths to `.env` file to load environment variables from. + * Paths to `.env` files to load environment variables from. * - * If not specified, the default behavior: - * - look for a `.env` file in the same directory as the Wrangler configuration file, or in the current working - * directory if no Wrangler configuration file is specified. - * - also look for a `.env.local` file in the same directory as the `.env` file. + * If defined only the files in the array will be considered for loading local dev variables. + * If left `undefined`, the default behavior is: + * - compute the project directory as that containing the Wrangler configuration file, + * or the current working directory if no Wrangler configuration file is specified. + * - look for `.env` and `.env.local` files in the project directory. * - if the `environment` option is specified, also look for `.env.` and `.env..local` - * files in the same directory as the `.env` file. + * files in the project directory + * - resulting in an `envFiles` array like: `[".env", ".env.local", ".env.", ".env..local"]`. + * + * The values from files earlier in the `envFiles` array (e.g. `envFiles[x]`) will be overridden by values from files later in the array (e.g. `envFiles[x+1)`). */ envFiles?: string[]; /** From 85c487e0e732d207e5f72b5d10357177bfb15844 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 18 Jul 2025 15:43:28 +0100 Subject: [PATCH 10/42] fixup! use `toMatchObject()` in tests --- .../nodejs-hybrid-app/tests/index.test.ts | 14 +- .../vite-plugin-cloudflare/e2e/basic.test.ts | 212 +++++++++--------- 2 files changed, 109 insertions(+), 117 deletions(-) diff --git a/fixtures/nodejs-hybrid-app/tests/index.test.ts b/fixtures/nodejs-hybrid-app/tests/index.test.ts index 1d61ad31c342..e2e6a5964e3f 100644 --- a/fixtures/nodejs-hybrid-app/tests/index.test.ts +++ b/fixtures/nodejs-hybrid-app/tests/index.test.ts @@ -93,19 +93,17 @@ describe("nodejs compat", () => { const { ip, port } = wrangler; const response = await fetch(`http://${ip}:${port}/process-env`); await expect(response.json()).resolves.toMatchObject({ - DB_HOSTNAME: "hh-pgsql-public.ebi.ac.uk", - DEV_VAR_FROM_DOT_ENV: "dev-var-from-dot-env", - }) - ); + DB_HOSTNAME: "hh-pgsql-public.ebi.ac.uk", + DEV_VAR_FROM_DOT_ENV: "dev-var-from-dot-env", + }); }); test("env contains vars", async ({ expect }) => { const { ip, port } = wrangler; const response = await fetch(`http://${ip}:${port}/env`); await expect(response.json()).resolves.toMatchObject({ - DB_HOSTNAME: "hh-pgsql-public.ebi.ac.uk", - DEV_VAR_FROM_DOT_ENV: "dev-var-from-dot-env", - }) - ); + DB_HOSTNAME: "hh-pgsql-public.ebi.ac.uk", + DEV_VAR_FROM_DOT_ENV: "dev-var-from-dot-env", + }); }); }); diff --git a/packages/vite-plugin-cloudflare/e2e/basic.test.ts b/packages/vite-plugin-cloudflare/e2e/basic.test.ts index 8f9894ea14b4..b8995a8b3027 100644 --- a/packages/vite-plugin-cloudflare/e2e/basic.test.ts +++ b/packages/vite-plugin-cloudflare/e2e/basic.test.ts @@ -39,124 +39,118 @@ describe("basic e2e tests", () => { SECRET_B: "dev-2", VAR_1: "var-1", }); + }); - test("will not load local dev vars from .env if there is a .dev.vars file", async ({ - expect, - onTestFinished, - }) => { - await writeFile( - projectPath + "/.env", - "SECRET_A=dot-env-1\nSECRET_B=dot-env-2" - ); - await writeFile( - projectPath + "/.dev.vars", - "SECRET_A=dev-dot-vars-1" - ); - onTestFinished(async () => { - await rm(projectPath + "/.env"); - await rm(projectPath + "/.dev.vars"); - }); - const proc = await runLongLived(pm, command, projectPath); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - SECRET_A: "dev-dot-vars-1", - VAR_1: "var-1", - }); + test("will not load local dev vars from .env if there is a .dev.vars file", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dot-env-1\nSECRET_B=dot-env-2" + ); + await writeFile( + projectPath + "/.dev.vars", + "SECRET_A=dev-dot-vars-1" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + await rm(projectPath + "/.dev.vars"); }); + const proc = await runLongLived(pm, command, projectPath); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + SECRET_A: "dev-dot-vars-1", + VAR_1: "var-1", + }); + }); - test("will not load local dev vars from .env if CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV is set to false", async ({ - expect, - onTestFinished, - }) => { - await writeFile( - projectPath + "/.env", - "SECRET_A=dot-env-1\nSECRET_B=dot-env-2" - ); - onTestFinished(async () => { - await rm(projectPath + "/.env"); - }); - const proc = await runLongLived(pm, command, projectPath, { - CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV: "false", - }); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - VAR_1: "var-1", - }); + test("will not load local dev vars from .env if CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV is set to false", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dot-env-1\nSECRET_B=dot-env-2" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + }); + const proc = await runLongLived(pm, command, projectPath, { + CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV: "false", }); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + VAR_1: "var-1", + }); + }); - test("can merge vars from wrangler configuration, .env, and .env.local", async ({ - expect, - onTestFinished, - }) => { - await writeFile( - projectPath + "/.env", - "SECRET_A=dev-1\nSECRET_B=dev-2" - ); - await writeFile( - projectPath + "/.env.local", - "SECRET_A=local-dev-1" - ); - onTestFinished(async () => { - await rm(projectPath + "/.env"); - await rm(projectPath + "/.env.local"); - }); - const proc = await runLongLived(pm, command, projectPath); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - SECRET_A: "local-dev-1", - SECRET_B: "dev-2", - VAR_1: "var-1", - }); + test("can merge vars from wrangler configuration, .env, and .env.local", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dev-1\nSECRET_B=dev-2" + ); + await writeFile(projectPath + "/.env.local", "SECRET_A=local-dev-1"); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + await rm(projectPath + "/.env.local"); }); + const proc = await runLongLived(pm, command, projectPath); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + SECRET_A: "local-dev-1", + SECRET_B: "dev-2", + VAR_1: "var-1", + }); + }); - test("can merge vars from wrangler configuration, .env, and .env.local, and environment specific files", async ({ - expect, - onTestFinished, - }) => { - await writeFile( - projectPath + "/.env", - "SECRET_A=dev-1\nSECRET_B=dev-2" - ); - await writeFile( - projectPath + "/.env.local", - "SECRET_A=local-dev-1" - ); - await writeFile( - projectPath + "/.env.staging", - "SECRET_B=staging-2\nSECRET_C=staging-3" - ); - await writeFile( - projectPath + "/.env.staging.local", - "SECRET_C=local-staging-3" - ); - onTestFinished(async () => { - await rm(projectPath + "/.env"); - await rm(projectPath + "/.env.local"); - await rm(projectPath + "/.env.staging"); - await rm(projectPath + "/.env.staging.local"); - }); - const proc = await runLongLived(pm, command, projectPath, { - CLOUDFLARE_ENV: "staging", - }); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - SECRET_A: "local-dev-1", - SECRET_B: "staging-2", - SECRET_C: "local-staging-3", - VAR_1: "var-1", - }); + test("can merge vars from wrangler configuration, .env, and .env.local, and environment specific files", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dev-1\nSECRET_B=dev-2" + ); + await writeFile(projectPath + "/.env.local", "SECRET_A=local-dev-1"); + await writeFile( + projectPath + "/.env.staging", + "SECRET_B=staging-2\nSECRET_C=staging-3" + ); + await writeFile( + projectPath + "/.env.staging.local", + "SECRET_C=local-staging-3" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + await rm(projectPath + "/.env.local"); + await rm(projectPath + "/.env.staging"); + await rm(projectPath + "/.env.staging.local"); + }); + const proc = await runLongLived(pm, command, projectPath, { + CLOUDFLARE_ENV: "staging", + }); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + SECRET_A: "local-dev-1", + SECRET_B: "staging-2", + SECRET_C: "local-staging-3", + VAR_1: "var-1", }); + }); - test("can read vars from process.env if CLOUDFLARE_INCLUDE_PROCESS_ENV is set", async ({ - expect, - }) => { - const proc = await runLongLived(pm, command, projectPath, { - CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", - }); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", // this proves we read the process.env - }); + test("can read vars from process.env if CLOUDFLARE_INCLUDE_PROCESS_ENV is set", async ({ + expect, + }) => { + const proc = await runLongLived(pm, command, projectPath, { + CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", + }); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", // this proves we read the process.env }); }); }); From 186d19ca0470aa6320fcf2967797109eb13f449f Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 18 Jul 2025 15:44:48 +0100 Subject: [PATCH 11/42] fixup! Add support for loading local vars from .env files to the vite-plugin --- packages/vite-plugin-cloudflare/src/dev-vars.ts | 4 ++-- packages/vite-plugin-cloudflare/src/index.ts | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/vite-plugin-cloudflare/src/dev-vars.ts b/packages/vite-plugin-cloudflare/src/dev-vars.ts index 0857205ecfa6..0dd4e4cfaca2 100644 --- a/packages/vite-plugin-cloudflare/src/dev-vars.ts +++ b/packages/vite-plugin-cloudflare/src/dev-vars.ts @@ -10,13 +10,13 @@ import type { * * Calls `unstable_getVarsForDev` with the current Cloudflare environment to get local dev variables from the `.dev.vars` and `.env` files. */ -export function getLocalDevVars( +export function getLocalDevVarsForPreview( configPath: string | undefined, cloudflareEnv: string | undefined ): string | undefined { const dotDevDotVars = unstable_getVarsForDev( configPath, - undefined, // We don't currently support setting a custom path to the `.env` files. + undefined, // We don't currently support setting a list of custom `.env` files. {}, // Don't pass actual vars since these will be loaded from the wrangler.json. cloudflareEnv ); diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index 9a5aefb8aa14..7a7f91c27014 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -40,7 +40,10 @@ import { getResolvedInspectorPort, } from "./debugging"; import { writeDeployConfig } from "./deploy-config"; -import { getLocalDevVars, hasLocalDevVarsFileChanged } from "./dev-vars"; +import { + getLocalDevVarsForPreview, + hasLocalDevVarsFileChanged, +} from "./dev-vars"; import { getDevMiniflareOptions, getEntryWorkerConfig, @@ -271,7 +274,7 @@ if (import.meta.hot) { config = workerConfig; if (workerConfig.configPath) { - const localDevVars = getLocalDevVars( + const localDevVars = getLocalDevVarsForPreview( workerConfig.configPath, resolvedPluginConfig.cloudflareEnv ); From 6cea665c900470d5c52981d2db5867a1b5f026f6 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 18 Jul 2025 16:38:51 +0100 Subject: [PATCH 12/42] review fixups --- .../src/api/integrations/platform/index.ts | 8 +-- .../wrangler/src/api/startDevWorker/types.ts | 6 ++- packages/wrangler/src/config/dot-env.ts | 25 ++++++---- packages/wrangler/src/dev.ts | 12 +++++ packages/wrangler/src/dev/dev-vars.ts | 49 ++++++++++--------- packages/wrangler/src/index.ts | 16 +++--- 6 files changed, 69 insertions(+), 47 deletions(-) diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 348863cd8bb6..55626c74508d 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -58,10 +58,12 @@ export type GetPlatformProxyOptions = { */ configPath?: string; /** - * Paths to `.env` files to load environment variables from. + * Paths to `.env` files to load environment variables from, relative to the project directory. * - * If defined only the files in the array will be considered for loading local dev variables. - * If left `undefined`, the default behavior is: + * The project directory is computed as the directory containing `configPath` or the current working directory if `configPath` is undefined. + * + * If `envFiles` is defined, only the files in the array will be considered for loading local dev variables. + * If `undefined`, the default behavior is: * - compute the project directory as that containing the Wrangler configuration file, * or the current working directory if no Wrangler configuration file is specified. * - look for `.env` and `.env.local` files in the project directory. diff --git a/packages/wrangler/src/api/startDevWorker/types.ts b/packages/wrangler/src/api/startDevWorker/types.ts index 37d5ec059b9b..c50374f8bc02 100644 --- a/packages/wrangler/src/api/startDevWorker/types.ts +++ b/packages/wrangler/src/api/startDevWorker/types.ts @@ -85,8 +85,10 @@ export interface StartDevWorkerInput { env?: string; /** - * The paths to the .env files to load for this worker, relative to the worker's directory. - * If not specified, defaults to the standard `.env` files, in the wrangler config directory or current working directory if no wrangler config is present. + * An array of paths to the .env files to load for this worker, relative to the project directory. + * + * If not specified, defaults to the standard `.env` files as given by `getDefaultEnvFiles()`. + * The project directory is where the Wrangler configuration file is located or the current working directory otherwise. */ envFiles?: string[]; diff --git a/packages/wrangler/src/config/dot-env.ts b/packages/wrangler/src/config/dot-env.ts index 47b479a2ace4..3009e9dc481e 100644 --- a/packages/wrangler/src/config/dot-env.ts +++ b/packages/wrangler/src/config/dot-env.ts @@ -4,21 +4,21 @@ import dotenvExpand from "dotenv-expand"; import { logger } from "../logger"; /** - * Generates the default set of paths for .env file loading. + * Generates the default array of `envFiles` for .env file loading. * - * The default order is `.env`, `.env.local`, `.env.`, and `.env..local` in that order. + * The default order is [`.env`, `.env.local`, `.env.`, `.env..local`]. + * + * @param env - The specific environment name (e.g., "staging") or `undefined` if no specific environment is set. + * @returns An array of strings representing the relative paths to the default .env files. */ -export function getDefaultEnvPaths( - basePath: string, - env: string | undefined -): string[] { +export function getDefaultEnvFiles(env: string | undefined): string[] { // Generate the default paths for .env files based on the provided base path and environment. - const envPaths = [basePath, basePath + ".local"]; + const envFiles = [".env", ".env.local"]; if (env !== undefined) { - envPaths.push(`${basePath}.${env}`); - envPaths.push(`${basePath}.${env}.local`); + envFiles.push(`.env.${env}`); + envFiles.push(`.env.${env}.local`); } - return envPaths; + return envFiles; } /** @@ -29,6 +29,11 @@ export function getDefaultEnvPaths( * * Further, once merged values are expanded, meaning that if a value references another variable * (e.g., `FOO=${BAR}`), it will be replaced with the value of `BAR` if it exists. + * + * @param envPaths - An array of absolute paths to .env files to load. + * @param options.includeProcessEnv - If true, will include the current process environment variables in the merged result. + * @param options.silent - If true, will not log any messages about the loaded .env files. + * @returns An object containing the merged and expanded environment variables. */ export function loadDotEnv( envPaths: string[], diff --git a/packages/wrangler/src/dev.ts b/packages/wrangler/src/dev.ts index 6e3701abc37d..c79cc432e397 100644 --- a/packages/wrangler/src/dev.ts +++ b/packages/wrangler/src/dev.ts @@ -865,6 +865,18 @@ function getResolvedSiteAssetPaths( ); } +/** + * Gets the bindings for the Cloudflare Worker. + * + * @param configParam The loaded configuration. + * @param env The environment to use, if any. + * @param envFiles An array of paths, relative to the project directory, of .env files to load. + * If `undefined` it defaults to the standard .env files from `getDefaultEnvFiles()`. + * @param local Whether the dev server should run locally. + * @param args Additional arguments for the dev server. + * @param remoteBindingsEnabled Whether remote bindings are enabled, defaults to the value of the `REMOTE_BINDINGS` flag. + * @returns The bindings for the Cloudflare Worker. + */ export function getBindings( configParam: Config, env: string | undefined, diff --git a/packages/wrangler/src/dev/dev-vars.ts b/packages/wrangler/src/dev/dev-vars.ts index 3172feffb28f..1802de0528d3 100644 --- a/packages/wrangler/src/dev/dev-vars.ts +++ b/packages/wrangler/src/dev/dev-vars.ts @@ -1,7 +1,7 @@ import * as path from "node:path"; import { maybeGetFile } from "@cloudflare/workers-shared"; import dotenv from "dotenv"; -import { getDefaultEnvPaths, loadDotEnv } from "../config/dot-env"; +import { getDefaultEnvFiles, loadDotEnv } from "../config/dot-env"; import { getCloudflareIncludeProcessEnvFromEnv, getCloudflareLoadDevVarsFromDotEnv, @@ -22,16 +22,24 @@ import type { Config } from "../config"; * Wrangler configuration). If the `--env ` option is set, we'll first look for * `.dev.vars.`. * - * If there are no `.dev.vars*` file, we will look for `.env*` files in the same directory. - * If the `--env-file ` option is set, we'll look for the `.env*` files at that path. + * If there are no `.dev.vars*` file, (and CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV is not "false") + * we will look for `.env*` files in the same directory. + * If the `envFiles` option is set, we'll look for the `.env` files at those paths instead of the defaults. * * Any values in these files (all formatted like `.env` files) will add to or override `vars` * bindings provided in the Wrangler configuration file. * + * @param configPath - The path to the Wrangler configuration file, if defined. + * @param envFiles - An array of paths to .env files to load; if `undefined` the default .env files will be used (see `getDefaultEnvFiles()`). + * The `envFiles` paths are resolved against the directory of the Wrangler configuration file, if there is one, otherwise against the current working directory. + * @param vars - The existing `vars` bindings from the Wrangler configuration. + * @param env - The specific environment name (e.g., "staging") or `undefined` if no specific environment is set. + * @param silent - If true, will not log any messages about the loaded .dev.vars files or .env files. + * @returns The merged `vars` bindings, including those loaded from `.dev.vars` or `.env` files. */ export function getVarsForDev( configPath: string | undefined, - envFilePaths: string[] | undefined, + envFiles: string[] | undefined, vars: Config["vars"], env: string | undefined, silent = false @@ -46,24 +54,19 @@ export function getVarsForDev( if (!silent) { logger.log(`Using vars defined in ${devVarsRelativePath}`); } - return { - ...vars, - ...loaded.parsed, - }; + return { ...vars, ...loaded.parsed }; } else if (getCloudflareLoadDevVarsFromDotEnv()) { - // If no .dev.vars files load vars from those in `envFilePaths` if defined or default .env files in the configuration directory. - const resolvedEnvFilePaths = ( - envFilePaths ?? getDefaultEnvPaths(".env", env) - ).map((p) => path.resolve(path.join(configDir, p))); + // If no .dev.vars files load vars from .env files instead. + const resolvedEnvFilePaths = (envFiles ?? getDefaultEnvFiles(env)).map( + (p) => path.resolve(configDir, p) + ); const dotEnvVars = loadDotEnv(resolvedEnvFilePaths, { includeProcessEnv: getCloudflareIncludeProcessEnvFromEnv(), silent, }); - return { - ...vars, - ...dotEnvVars, - }; + return { ...vars, ...dotEnvVars }; } else { + // Just return the vars from the Wrangler configuration. return vars; } } @@ -90,22 +93,20 @@ function tryLoadDotDevDotVars(basePath: string): DotDevDotVars | undefined { `Failed to load local dev variables file "${path.relative(".", basePath)}":`, e ); + return { path: basePath, parsed: {} }; } } /** - * Loads a .dev.vars (or .env style) file from `envPath`, preferring to read `${envPath}.${env}` if + * Loads a .dev.vars file from `envPath`, preferring to read `${envPath}.${env}` if * `env` is defined and that file exists. */ export function loadDotDevDotVars( envPath: string, env?: string ): DotDevDotVars | undefined { - if (env === undefined) { - return tryLoadDotDevDotVars(envPath); - } else { - return ( - tryLoadDotDevDotVars(`${envPath}.${env}`) ?? tryLoadDotDevDotVars(envPath) - ); - } + return ( + (env !== undefined && tryLoadDotDevDotVars(`${envPath}.${env}`)) || + tryLoadDotDevDotVars(envPath) + ); } diff --git a/packages/wrangler/src/index.ts b/packages/wrangler/src/index.ts index e22d2fd0cdcf..1c6adbf5a3c9 100644 --- a/packages/wrangler/src/index.ts +++ b/packages/wrangler/src/index.ts @@ -23,7 +23,7 @@ import { import { checkNamespace, checkStartupCommand } from "./check/commands"; import { cloudchamber } from "./cloudchamber"; import { experimental_readRawConfig, readConfig } from "./config"; -import { getDefaultEnvPaths, loadDotEnv } from "./config/dot-env"; +import { getDefaultEnvFiles, loadDotEnv } from "./config/dot-env"; import { containers } from "./containers"; import { demandSingleValue } from "./core"; import { CommandRegistry } from "./core/CommandRegistry"; @@ -429,14 +429,14 @@ export function createCLIParser(argv: string[]) { }) .check((args) => { // Set process environment params from `.env` files if available. + const resolvedEnvFilePaths = ( + args["env-file"] ?? getDefaultEnvFiles(args.env) + ).map((p) => resolve(p)); process.env = - loadDotEnv( - args["env-file"] ?? getDefaultEnvPaths(resolve(".env"), args.env), - { - includeProcessEnv: true, - silent: true, - } - ) ?? process.env; + loadDotEnv(resolvedEnvFilePaths, { + includeProcessEnv: true, + silent: true, + }) ?? process.env; // Write a session entry to the output file (if there is one). writeOutput({ From b363993c80c9c0b6a58c14bcca3d8f158a050f54 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 18 Jul 2025 18:00:39 +0100 Subject: [PATCH 13/42] fix up snapshots after rebase --- .../wrangler/src/__tests__/containers/push.test.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/wrangler/src/__tests__/containers/push.test.ts b/packages/wrangler/src/__tests__/containers/push.test.ts index 54d1d08a4615..84dcd6c7e67e 100644 --- a/packages/wrangler/src/__tests__/containers/push.test.ts +++ b/packages/wrangler/src/__tests__/containers/push.test.ts @@ -38,11 +38,12 @@ describe("containers push", () => { TAG [string] GLOBAL FLAGS - -c, --config Path to Wrangler configuration file [string] - --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - -h, --help Show help [boolean] - -v, --version Show version number [boolean] + -c, --config Path to Wrangler configuration file [string] + --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] + -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] + --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + -h, --help Show help [boolean] + -v, --version Show version number [boolean] OPTIONS --path-to-docker Path to your docker binary if it's not on $PATH [string] [default: \\"docker\\"]" From 281b6c4c30ebd064425b819aabafc7dece230cd5 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 18 Jul 2025 18:17:28 +0100 Subject: [PATCH 14/42] more fixups --- packages/wrangler/src/__tests__/ai.test.ts | 4 +- packages/wrangler/src/__tests__/cert.test.ts | 2 +- .../src/__tests__/cloudchamber/create.test.ts | 2 +- .../src/__tests__/cloudchamber/curl.test.ts | 2 +- .../src/__tests__/cloudchamber/delete.test.ts | 2 +- .../src/__tests__/cloudchamber/images.test.ts | 4 +- .../src/__tests__/cloudchamber/list.test.ts | 2 +- .../src/__tests__/cloudchamber/modify.test.ts | 2 +- .../src/__tests__/containers/delete.test.ts | 2 +- .../src/__tests__/containers/info.test.ts | 2 +- .../src/__tests__/containers/list.test.ts | 2 +- .../src/__tests__/containers/push.test.ts | 2 +- packages/wrangler/src/__tests__/d1/d1.test.ts | 8 ++-- .../src/__tests__/deployments.test.ts | 2 +- packages/wrangler/src/__tests__/docs.test.ts | 2 +- .../wrangler/src/__tests__/hyperdrive.test.ts | 4 +- packages/wrangler/src/__tests__/index.test.ts | 14 +++--- packages/wrangler/src/__tests__/kv.test.ts | 30 ++++++------- .../src/__tests__/mtls-certificates.test.ts | 2 +- .../src/__tests__/pages/deploy.test.ts | 2 +- .../src/__tests__/pages/pages.test.ts | 14 +++--- .../wrangler/src/__tests__/pipelines.test.ts | 4 +- .../wrangler/src/__tests__/pubsub.test.ts | 6 +-- .../wrangler/src/__tests__/queues.test.ts | 30 ++++++------- packages/wrangler/src/__tests__/r2.test.ts | 44 +++++++++---------- .../src/__tests__/secrets-store.test.ts | 4 +- .../src/__tests__/vectorize/vectorize.test.ts | 8 ++-- .../__tests__/versions/versions.help.test.ts | 4 +- .../src/__tests__/worker-namespace.test.ts | 10 ++--- .../wrangler/src/__tests__/workflows.test.ts | 4 +- 30 files changed, 110 insertions(+), 110 deletions(-) diff --git a/packages/wrangler/src/__tests__/ai.test.ts b/packages/wrangler/src/__tests__/ai.test.ts index d04e4f58ae81..17f270b9b0d6 100644 --- a/packages/wrangler/src/__tests__/ai.test.ts +++ b/packages/wrangler/src/__tests__/ai.test.ts @@ -29,7 +29,7 @@ describe("ai help", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -59,7 +59,7 @@ describe("ai help", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/cert.test.ts b/packages/wrangler/src/__tests__/cert.test.ts index 2bdf72b20447..702e1b269776 100644 --- a/packages/wrangler/src/__tests__/cert.test.ts +++ b/packages/wrangler/src/__tests__/cert.test.ts @@ -487,7 +487,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/cloudchamber/create.test.ts b/packages/wrangler/src/__tests__/cloudchamber/create.test.ts index 5a3c09ce52f9..7029c59a3c9d 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/create.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/create.test.ts @@ -108,7 +108,7 @@ describe("cloudchamber create", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/cloudchamber/curl.test.ts b/packages/wrangler/src/__tests__/cloudchamber/curl.test.ts index 5d663bbb1a14..3969c54e122c 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/curl.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/curl.test.ts @@ -42,7 +42,7 @@ describe("cloudchamber curl", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/cloudchamber/delete.test.ts b/packages/wrangler/src/__tests__/cloudchamber/delete.test.ts index 4d6ae4215741..9eaffeacdb1f 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/delete.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/delete.test.ts @@ -38,7 +38,7 @@ describe("cloudchamber delete", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/cloudchamber/images.test.ts b/packages/wrangler/src/__tests__/cloudchamber/images.test.ts index e7b96dc09180..c36692afcaf2 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/images.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/images.test.ts @@ -45,7 +45,7 @@ describe("cloudchamber image", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -192,7 +192,7 @@ describe("cloudchamber image list", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/cloudchamber/list.test.ts b/packages/wrangler/src/__tests__/cloudchamber/list.test.ts index d00d9bc553f8..38761fee5d8d 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/list.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/list.test.ts @@ -39,7 +39,7 @@ describe("cloudchamber list", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/cloudchamber/modify.test.ts b/packages/wrangler/src/__tests__/cloudchamber/modify.test.ts index 9f1b2a3c6c65..ff0a745a571d 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/modify.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/modify.test.ts @@ -76,7 +76,7 @@ describe("cloudchamber modify", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/containers/delete.test.ts b/packages/wrangler/src/__tests__/containers/delete.test.ts index 30e35119f18b..63ace1eed61c 100644 --- a/packages/wrangler/src/__tests__/containers/delete.test.ts +++ b/packages/wrangler/src/__tests__/containers/delete.test.ts @@ -37,7 +37,7 @@ describe("containers delete", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/containers/info.test.ts b/packages/wrangler/src/__tests__/containers/info.test.ts index 29138e93fd39..330c7e9e1c35 100644 --- a/packages/wrangler/src/__tests__/containers/info.test.ts +++ b/packages/wrangler/src/__tests__/containers/info.test.ts @@ -38,7 +38,7 @@ describe("containers info", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/containers/list.test.ts b/packages/wrangler/src/__tests__/containers/list.test.ts index 87acd22a7c2f..d2ba943228de 100644 --- a/packages/wrangler/src/__tests__/containers/list.test.ts +++ b/packages/wrangler/src/__tests__/containers/list.test.ts @@ -33,7 +33,7 @@ describe("containers list", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/containers/push.test.ts b/packages/wrangler/src/__tests__/containers/push.test.ts index 84dcd6c7e67e..bbc60f04fd3e 100644 --- a/packages/wrangler/src/__tests__/containers/push.test.ts +++ b/packages/wrangler/src/__tests__/containers/push.test.ts @@ -41,7 +41,7 @@ describe("containers push", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/d1/d1.test.ts b/packages/wrangler/src/__tests__/d1/d1.test.ts index 2e35a325d53d..67873c458088 100644 --- a/packages/wrangler/src/__tests__/d1/d1.test.ts +++ b/packages/wrangler/src/__tests__/d1/d1.test.ts @@ -31,7 +31,7 @@ describe("d1", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -68,7 +68,7 @@ describe("d1", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -92,7 +92,7 @@ describe("d1", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -114,7 +114,7 @@ describe("d1", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/deployments.test.ts b/packages/wrangler/src/__tests__/deployments.test.ts index 432b5056a26a..0a50835b3ca9 100644 --- a/packages/wrangler/src/__tests__/deployments.test.ts +++ b/packages/wrangler/src/__tests__/deployments.test.ts @@ -63,7 +63,7 @@ describe("deployments", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/docs.test.ts b/packages/wrangler/src/__tests__/docs.test.ts index e4ca6fb75813..d1c272628626 100644 --- a/packages/wrangler/src/__tests__/docs.test.ts +++ b/packages/wrangler/src/__tests__/docs.test.ts @@ -50,7 +50,7 @@ describe("wrangler docs", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/hyperdrive.test.ts b/packages/wrangler/src/__tests__/hyperdrive.test.ts index 3633c0312d34..acf652e7332c 100644 --- a/packages/wrangler/src/__tests__/hyperdrive.test.ts +++ b/packages/wrangler/src/__tests__/hyperdrive.test.ts @@ -40,7 +40,7 @@ describe("hyperdrive help", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -73,7 +73,7 @@ describe("hyperdrive help", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/index.test.ts b/packages/wrangler/src/__tests__/index.test.ts index 66958b8c0f69..2dcb7f059b3c 100644 --- a/packages/wrangler/src/__tests__/index.test.ts +++ b/packages/wrangler/src/__tests__/index.test.ts @@ -73,7 +73,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -134,7 +134,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -206,7 +206,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -230,7 +230,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -254,7 +254,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -277,7 +277,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -299,7 +299,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/kv.test.ts b/packages/wrangler/src/__tests__/kv.test.ts index b0a21107032d..2c2b528c1742 100644 --- a/packages/wrangler/src/__tests__/kv.test.ts +++ b/packages/wrangler/src/__tests__/kv.test.ts @@ -51,7 +51,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -74,7 +74,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -104,7 +104,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -150,7 +150,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -183,7 +183,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -458,7 +458,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -850,7 +850,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -894,7 +894,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -940,7 +940,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -984,7 +984,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -1028,7 +1028,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -1074,7 +1074,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -1466,7 +1466,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -1505,7 +1505,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -1545,7 +1545,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/mtls-certificates.test.ts b/packages/wrangler/src/__tests__/mtls-certificates.test.ts index 3be6ea71bbb4..88ad24ab4f64 100644 --- a/packages/wrangler/src/__tests__/mtls-certificates.test.ts +++ b/packages/wrangler/src/__tests__/mtls-certificates.test.ts @@ -405,7 +405,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/pages/deploy.test.ts b/packages/wrangler/src/__tests__/pages/deploy.test.ts index f976bb0554b0..c2ea3fc60a3e 100644 --- a/packages/wrangler/src/__tests__/pages/deploy.test.ts +++ b/packages/wrangler/src/__tests__/pages/deploy.test.ts @@ -65,7 +65,7 @@ describe("pages deploy", () => { GLOBAL FLAGS --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/pages/pages.test.ts b/packages/wrangler/src/__tests__/pages/pages.test.ts index 00a8ca5094fd..9737c46e59c1 100644 --- a/packages/wrangler/src/__tests__/pages/pages.test.ts +++ b/packages/wrangler/src/__tests__/pages/pages.test.ts @@ -33,7 +33,7 @@ describe("pages", () => { GLOBAL FLAGS --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -54,7 +54,7 @@ describe("pages", () => { GLOBAL FLAGS --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -103,7 +103,7 @@ describe("pages", () => { GLOBAL FLAGS --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -127,7 +127,7 @@ describe("pages", () => { GLOBAL FLAGS --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -147,7 +147,7 @@ describe("pages", () => { GLOBAL FLAGS --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -180,7 +180,7 @@ describe("pages", () => { GLOBAL FLAGS --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -200,7 +200,7 @@ describe("pages", () => { GLOBAL FLAGS --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/pipelines.test.ts b/packages/wrangler/src/__tests__/pipelines.test.ts index 2f54df13f977..86c622f6b418 100644 --- a/packages/wrangler/src/__tests__/pipelines.test.ts +++ b/packages/wrangler/src/__tests__/pipelines.test.ts @@ -287,7 +287,7 @@ describe("pipelines", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -331,7 +331,7 @@ describe("pipelines", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/pubsub.test.ts b/packages/wrangler/src/__tests__/pubsub.test.ts index 84d010156b56..295f2322b1e0 100644 --- a/packages/wrangler/src/__tests__/pubsub.test.ts +++ b/packages/wrangler/src/__tests__/pubsub.test.ts @@ -38,7 +38,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -72,7 +72,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -201,7 +201,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/queues.test.ts b/packages/wrangler/src/__tests__/queues.test.ts index 4f0e4cc776e6..a0a8ef86ad6b 100644 --- a/packages/wrangler/src/__tests__/queues.test.ts +++ b/packages/wrangler/src/__tests__/queues.test.ts @@ -43,7 +43,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -118,7 +118,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -267,7 +267,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -488,7 +488,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -643,7 +643,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -713,7 +713,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -762,7 +762,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -1085,7 +1085,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -1474,7 +1474,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -1522,7 +1522,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -1654,7 +1654,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -1743,7 +1743,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -1907,7 +1907,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -2018,7 +2018,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -2121,7 +2121,7 @@ describe("wrangler", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/r2.test.ts b/packages/wrangler/src/__tests__/r2.test.ts index 05217cc8adb7..eb72165040b4 100644 --- a/packages/wrangler/src/__tests__/r2.test.ts +++ b/packages/wrangler/src/__tests__/r2.test.ts @@ -104,7 +104,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -134,7 +134,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -171,7 +171,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -213,7 +213,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -322,7 +322,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -357,7 +357,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -481,7 +481,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -512,7 +512,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -579,7 +579,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -644,7 +644,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -713,7 +713,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -806,7 +806,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -851,7 +851,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -904,7 +904,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -972,7 +972,7 @@ describe("r2", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -1029,7 +1029,7 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -1062,7 +1062,7 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -1152,7 +1152,7 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -1373,7 +1373,7 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -1735,7 +1735,7 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -1895,7 +1895,7 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -3225,7 +3225,7 @@ For more details, refer to: https://developers.cloudflare.com/r2/api/s3/tokens/" -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/secrets-store.test.ts b/packages/wrangler/src/__tests__/secrets-store.test.ts index 753b5d4e70d5..c46169ad3622 100644 --- a/packages/wrangler/src/__tests__/secrets-store.test.ts +++ b/packages/wrangler/src/__tests__/secrets-store.test.ts @@ -37,7 +37,7 @@ describe("secrets-store help", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -67,7 +67,7 @@ describe("secrets-store help", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/vectorize/vectorize.test.ts b/packages/wrangler/src/__tests__/vectorize/vectorize.test.ts index 39a7130ee341..ec48320f5df8 100644 --- a/packages/wrangler/src/__tests__/vectorize/vectorize.test.ts +++ b/packages/wrangler/src/__tests__/vectorize/vectorize.test.ts @@ -42,7 +42,7 @@ describe("vectorize help", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -83,7 +83,7 @@ describe("vectorize help", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -112,7 +112,7 @@ describe("vectorize help", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] @@ -145,7 +145,7 @@ describe("vectorize help", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean] diff --git a/packages/wrangler/src/__tests__/versions/versions.help.test.ts b/packages/wrangler/src/__tests__/versions/versions.help.test.ts index 48e376df89e3..b5a3537cdd6d 100644 --- a/packages/wrangler/src/__tests__/versions/versions.help.test.ts +++ b/packages/wrangler/src/__tests__/versions/versions.help.test.ts @@ -26,7 +26,7 @@ describe("versions --help", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -58,7 +58,7 @@ describe("versions subhelp", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/worker-namespace.test.ts b/packages/wrangler/src/__tests__/worker-namespace.test.ts index 165ff695b6ee..00e2e4e31583 100644 --- a/packages/wrangler/src/__tests__/worker-namespace.test.ts +++ b/packages/wrangler/src/__tests__/worker-namespace.test.ts @@ -45,7 +45,7 @@ describe("dispatch-namespace", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]", "warn": "", @@ -99,7 +99,7 @@ describe("dispatch-namespace", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -151,7 +151,7 @@ describe("dispatch-namespace", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -212,7 +212,7 @@ describe("dispatch-namespace", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); @@ -324,7 +324,7 @@ describe("dispatch-namespace", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" `); diff --git a/packages/wrangler/src/__tests__/workflows.test.ts b/packages/wrangler/src/__tests__/workflows.test.ts index ee907371723e..051b17044cf2 100644 --- a/packages/wrangler/src/__tests__/workflows.test.ts +++ b/packages/wrangler/src/__tests__/workflows.test.ts @@ -128,7 +128,7 @@ describe("wrangler workflows", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" ` @@ -160,7 +160,7 @@ describe("wrangler workflows", () => { -c, --config Path to Wrangler configuration file [string] --cwd Run as if Wrangler was started in the specified directory instead of the current working directory [string] -e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string] - --env-file Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones [array] + --env-file Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files [array] -h, --help Show help [boolean] -v, --version Show version number [boolean]" ` From 863a09e963c8dbe5d34bc14be9e38219719d6576 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 18 Jul 2025 18:17:39 +0100 Subject: [PATCH 15/42] more fixups --- packages/wrangler/src/config/dot-env.ts | 2 +- packages/wrangler/src/index.ts | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/wrangler/src/config/dot-env.ts b/packages/wrangler/src/config/dot-env.ts index 3009e9dc481e..a890878de844 100644 --- a/packages/wrangler/src/config/dot-env.ts +++ b/packages/wrangler/src/config/dot-env.ts @@ -38,7 +38,7 @@ export function getDefaultEnvFiles(env: string | undefined): string[] { export function loadDotEnv( envPaths: string[], { includeProcessEnv, silent }: { includeProcessEnv: boolean; silent: boolean } -): dotenv.DotenvParseOutput | undefined { +): dotenv.DotenvParseOutput { // The `parsedEnv` object will be mutated to contain the merged values. const parsedEnv = {}; for (const envPath of envPaths) { diff --git a/packages/wrangler/src/index.ts b/packages/wrangler/src/index.ts index 1c6adbf5a3c9..a40efc9e13ba 100644 --- a/packages/wrangler/src/index.ts +++ b/packages/wrangler/src/index.ts @@ -404,7 +404,7 @@ export function createCLIParser(argv: string[]) { }) .option("env-file", { describe: - "Path to an .env file to load - can be specified multiple times - earlier ones are overridden by later ones", + "Path to an .env file to load - can be specified multiple times - values from earlier files are overridden by values in later files", type: "string", array: true, requiresArg: true, @@ -432,11 +432,10 @@ export function createCLIParser(argv: string[]) { const resolvedEnvFilePaths = ( args["env-file"] ?? getDefaultEnvFiles(args.env) ).map((p) => resolve(p)); - process.env = - loadDotEnv(resolvedEnvFilePaths, { - includeProcessEnv: true, - silent: true, - }) ?? process.env; + process.env = loadDotEnv(resolvedEnvFilePaths, { + includeProcessEnv: true, + silent: true, + }); // Write a session entry to the output file (if there is one). writeOutput({ From 6bd04906a30852551b7bfe877a4f40d1bcc6b7ef Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Sun, 20 Jul 2025 22:08:53 +0100 Subject: [PATCH 16/42] simplify boolean env var defaults --- .../wrangler/src/environment-variables/misc-variables.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/wrangler/src/environment-variables/misc-variables.ts b/packages/wrangler/src/environment-variables/misc-variables.ts index 3333c52c4d21..acab5c02108b 100644 --- a/packages/wrangler/src/environment-variables/misc-variables.ts +++ b/packages/wrangler/src/environment-variables/misc-variables.ts @@ -145,9 +145,7 @@ function getStagingSubdomain(): string { */ export const getSanitizeLogs = getBooleanEnvironmentVariableFactory({ variableName: "WRANGLER_LOG_SANITIZE", - defaultValue() { - return true; - }, + defaultValue: true, }); /** @@ -281,7 +279,7 @@ export const getDockerPath = getEnvironmentVariableFactory({ export const getCloudflareLoadDevVarsFromDotEnv = getBooleanEnvironmentVariableFactory({ variableName: "CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV", - defaultValue: () => true, + defaultValue: true, }); /** @@ -290,5 +288,5 @@ export const getCloudflareLoadDevVarsFromDotEnv = export const getCloudflareIncludeProcessEnvFromEnv = getBooleanEnvironmentVariableFactory({ variableName: "CLOUDFLARE_INCLUDE_PROCESS_ENV", - defaultValue: () => false, + defaultValue: false, }); From 75ba0d238677df6be14df4f5a694b1f304936e61 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Sun, 20 Jul 2025 22:14:52 +0100 Subject: [PATCH 17/42] review fixups --- .changeset/moody-breads-pump.md | 4 ++-- packages/wrangler/src/dev/dev-vars.ts | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.changeset/moody-breads-pump.md b/.changeset/moody-breads-pump.md index 8f0695f03472..b1fd2a437728 100644 --- a/.changeset/moody-breads-pump.md +++ b/.changeset/moody-breads-pump.md @@ -15,6 +15,6 @@ Further details: - In `vite build` the local vars will be computed and stored in a `.dev.vars` file next to the compiled Worker code, so that `vite preview` can use them. - The `wrangler types` command will similarly read the `.env` files (if no `.dev.vars` files) in order to generate the `Env` interface. -- If the `CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV` environment variable is `false` then local dev variables will not be loaded from `.env` files. -- If the `CLOUDFLARE_INCLUDE_PROCESS_ENV` environment variable is `true` then all the environment variables found on `process.env` will be included as local dev vars. +- If the `CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV` environment variable is `"false"` then local dev variables will not be loaded from `.env` files. +- If the `CLOUDFLARE_INCLUDE_PROCESS_ENV` environment variable is `"true"` then all the environment variables found on `process.env` will be included as local dev vars. - Wrangler (but not Vite plugin) also now supports the `--env-file=` global CLI option. This affects both loading `.env` to configure Wrangler the tool as well as loading local dev vars. diff --git a/packages/wrangler/src/dev/dev-vars.ts b/packages/wrangler/src/dev/dev-vars.ts index 1802de0528d3..5ea290ad988a 100644 --- a/packages/wrangler/src/dev/dev-vars.ts +++ b/packages/wrangler/src/dev/dev-vars.ts @@ -89,11 +89,10 @@ function tryLoadDotDevDotVars(basePath: string): DotDevDotVars | undefined { const parsed = dotenv.parse(contents); return { path: basePath, parsed }; } catch (e) { - logger.debug( + throw new Error( `Failed to load local dev variables file "${path.relative(".", basePath)}":`, - e + { cause: e } ); - return { path: basePath, parsed: {} }; } } From cc130a6a5a53f219942603357712d3f141b968ff Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 21 Jul 2025 08:36:16 +0100 Subject: [PATCH 18/42] skip buildAndPreview test on Windows --- .../vite-plugin-cloudflare/e2e/basic.test.ts | 271 +++++++++--------- 1 file changed, 141 insertions(+), 130 deletions(-) diff --git a/packages/vite-plugin-cloudflare/e2e/basic.test.ts b/packages/vite-plugin-cloudflare/e2e/basic.test.ts index b8995a8b3027..ce566f06e640 100644 --- a/packages/vite-plugin-cloudflare/e2e/basic.test.ts +++ b/packages/vite-plugin-cloudflare/e2e/basic.test.ts @@ -2,6 +2,7 @@ import { rm, writeFile } from "node:fs/promises"; import { describe, test } from "vitest"; import { fetchJson, runLongLived, seed, waitForReady } from "./helpers.js"; +const isWindows = process.platform === "win32"; const packageManagers = ["pnpm", "npm", "yarn"] as const; const commands = ["dev", "buildAndPreview"] as const; @@ -10,150 +11,160 @@ describe("basic e2e tests", () => { const projectPath = seed("basic", pm); describe.each(commands)('with "%s" command', (command) => { - test("can serve a Worker that uses a Node.js API (crypto)", async ({ - expect, - }) => { - const proc = await runLongLived(pm, command, projectPath); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/api/")).toEqual({ - name: "Cloudflare", - }); - }); - - describe("environment variables", () => { - test("can read vars from wrangler configuration and .env", async ({ - expect, - onTestFinished, - }) => { - await writeFile( - projectPath + "/.env", - "SECRET_A=dev-1\nSECRET_B=dev-2" - ); - onTestFinished(async () => { - await rm(projectPath + "/.env"); - }); + test.skipIf(isWindows && command === "buildAndPreview")( + "can serve a Worker that uses a Node.js API (crypto)", + async ({ expect }) => { const proc = await runLongLived(pm, command, projectPath); const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - SECRET_A: "dev-1", - SECRET_B: "dev-2", - VAR_1: "var-1", + expect(await fetchJson(url + "/api/")).toEqual({ + name: "Cloudflare", }); - }); + } + ); - test("will not load local dev vars from .env if there is a .dev.vars file", async ({ - expect, - onTestFinished, - }) => { - await writeFile( - projectPath + "/.env", - "SECRET_A=dot-env-1\nSECRET_B=dot-env-2" - ); - await writeFile( - projectPath + "/.dev.vars", - "SECRET_A=dev-dot-vars-1" - ); - onTestFinished(async () => { - await rm(projectPath + "/.env"); - await rm(projectPath + "/.dev.vars"); - }); - const proc = await runLongLived(pm, command, projectPath); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - SECRET_A: "dev-dot-vars-1", - VAR_1: "var-1", + describe.skipIf(isWindows && command === "buildAndPreview")( + "environment variables", + () => { + test("can read vars from wrangler configuration and .env", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dev-1\nSECRET_B=dev-2" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + }); + const proc = await runLongLived(pm, command, projectPath); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + SECRET_A: "dev-1", + SECRET_B: "dev-2", + VAR_1: "var-1", + }); }); - }); - test("will not load local dev vars from .env if CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV is set to false", async ({ - expect, - onTestFinished, - }) => { - await writeFile( - projectPath + "/.env", - "SECRET_A=dot-env-1\nSECRET_B=dot-env-2" - ); - onTestFinished(async () => { - await rm(projectPath + "/.env"); - }); - const proc = await runLongLived(pm, command, projectPath, { - CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV: "false", - }); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - VAR_1: "var-1", + test("will not load local dev vars from .env if there is a .dev.vars file", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dot-env-1\nSECRET_B=dot-env-2" + ); + await writeFile( + projectPath + "/.dev.vars", + "SECRET_A=dev-dot-vars-1" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + await rm(projectPath + "/.dev.vars"); + }); + const proc = await runLongLived(pm, command, projectPath); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + SECRET_A: "dev-dot-vars-1", + VAR_1: "var-1", + }); }); - }); - test("can merge vars from wrangler configuration, .env, and .env.local", async ({ - expect, - onTestFinished, - }) => { - await writeFile( - projectPath + "/.env", - "SECRET_A=dev-1\nSECRET_B=dev-2" - ); - await writeFile(projectPath + "/.env.local", "SECRET_A=local-dev-1"); - onTestFinished(async () => { - await rm(projectPath + "/.env"); - await rm(projectPath + "/.env.local"); - }); - const proc = await runLongLived(pm, command, projectPath); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - SECRET_A: "local-dev-1", - SECRET_B: "dev-2", - VAR_1: "var-1", + test("will not load local dev vars from .env if CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV is set to false", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dot-env-1\nSECRET_B=dot-env-2" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + }); + const proc = await runLongLived(pm, command, projectPath, { + CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV: "false", + }); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + VAR_1: "var-1", + }); }); - }); - test("can merge vars from wrangler configuration, .env, and .env.local, and environment specific files", async ({ - expect, - onTestFinished, - }) => { - await writeFile( - projectPath + "/.env", - "SECRET_A=dev-1\nSECRET_B=dev-2" - ); - await writeFile(projectPath + "/.env.local", "SECRET_A=local-dev-1"); - await writeFile( - projectPath + "/.env.staging", - "SECRET_B=staging-2\nSECRET_C=staging-3" - ); - await writeFile( - projectPath + "/.env.staging.local", - "SECRET_C=local-staging-3" - ); - onTestFinished(async () => { - await rm(projectPath + "/.env"); - await rm(projectPath + "/.env.local"); - await rm(projectPath + "/.env.staging"); - await rm(projectPath + "/.env.staging.local"); - }); - const proc = await runLongLived(pm, command, projectPath, { - CLOUDFLARE_ENV: "staging", - }); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - SECRET_A: "local-dev-1", - SECRET_B: "staging-2", - SECRET_C: "local-staging-3", - VAR_1: "var-1", + test("can merge vars from wrangler configuration, .env, and .env.local", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dev-1\nSECRET_B=dev-2" + ); + await writeFile( + projectPath + "/.env.local", + "SECRET_A=local-dev-1" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + await rm(projectPath + "/.env.local"); + }); + const proc = await runLongLived(pm, command, projectPath); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + SECRET_A: "local-dev-1", + SECRET_B: "dev-2", + VAR_1: "var-1", + }); }); - }); - test("can read vars from process.env if CLOUDFLARE_INCLUDE_PROCESS_ENV is set", async ({ - expect, - }) => { - const proc = await runLongLived(pm, command, projectPath, { - CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", + test("can merge vars from wrangler configuration, .env, and .env.local, and environment specific files", async ({ + expect, + onTestFinished, + }) => { + await writeFile( + projectPath + "/.env", + "SECRET_A=dev-1\nSECRET_B=dev-2" + ); + await writeFile( + projectPath + "/.env.local", + "SECRET_A=local-dev-1" + ); + await writeFile( + projectPath + "/.env.staging", + "SECRET_B=staging-2\nSECRET_C=staging-3" + ); + await writeFile( + projectPath + "/.env.staging.local", + "SECRET_C=local-staging-3" + ); + onTestFinished(async () => { + await rm(projectPath + "/.env"); + await rm(projectPath + "/.env.local"); + await rm(projectPath + "/.env.staging"); + await rm(projectPath + "/.env.staging.local"); + }); + const proc = await runLongLived(pm, command, projectPath, { + CLOUDFLARE_ENV: "staging", + }); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + SECRET_A: "local-dev-1", + SECRET_B: "staging-2", + SECRET_C: "local-staging-3", + VAR_1: "var-1", + }); }); - const url = await waitForReady(proc); - expect(await fetchJson(url + "/env/")).toMatchObject({ - CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", // this proves we read the process.env + + test("can read vars from process.env if CLOUDFLARE_INCLUDE_PROCESS_ENV is set", async ({ + expect, + }) => { + const proc = await runLongLived(pm, command, projectPath, { + CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", + }); + const url = await waitForReady(proc); + expect(await fetchJson(url + "/env/")).toMatchObject({ + CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", // this proves we read the process.env + }); }); - }); - }); + } + ); // This test checks that wrapped bindings which rely on additional workers with an authed connection to the CF API work // They are skipped if you have not provided the necessary account id and api token. From 9a8459254f55906e486f69540338293496e28fd2 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 25 Jul 2025 09:44:48 +0100 Subject: [PATCH 19/42] move config update handling to a devServer watcher rather than hotUpdate --- .github/workflows/test-and-check.yml | 1 + .../playground/turbo.json | 9 ++ .../playground/vitest.config.e2e.ts | 5 +- .../src/cloudflare-environment.ts | 6 +- packages/vite-plugin-cloudflare/src/index.ts | 84 ++++++++++++++----- pnpm-lock.yaml | 4 +- 6 files changed, 83 insertions(+), 26 deletions(-) create mode 100644 packages/vite-plugin-cloudflare/playground/turbo.json diff --git a/.github/workflows/test-and-check.yml b/.github/workflows/test-and-check.yml index f50f1824c61d..b6023b3e1fd0 100644 --- a/.github/workflows/test-and-check.yml +++ b/.github/workflows/test-and-check.yml @@ -168,6 +168,7 @@ jobs: WRANGLER_LOG_PATH: ${{ runner.temp }}/wrangler-debug-logs/ TEST_REPORT_PATH: ${{ runner.temp }}/test-report/index.html CI_OS: ${{ matrix.description }} + NODE_DEBUG: "@cloudflare:vite-plugin" - name: Upload turbo logs if: always() diff --git a/packages/vite-plugin-cloudflare/playground/turbo.json b/packages/vite-plugin-cloudflare/playground/turbo.json new file mode 100644 index 000000000000..3fca6bdb5963 --- /dev/null +++ b/packages/vite-plugin-cloudflare/playground/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://turbo.build/schema.json", + "extends": ["//"], + "tasks": { + "test:ci": { + "env": ["NODE_DEBUG"] + } + } +} diff --git a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts index c5268a6ca6b8..c8dad65bcfe1 100644 --- a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts +++ b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts @@ -1,5 +1,8 @@ +import util from "node:util"; import { defineConfig } from "vitest/config"; +const debuglog = util.debuglog("@cloudflare:vite-plugin"); + export default defineConfig({ test: { // We run these tests in a single fork to avoid them running in parallel. @@ -10,7 +13,7 @@ export default defineConfig({ setupFiles: ["./vitest-setup.ts"], globalSetup: ["./vitest-global-setup.ts"], reporters: "dot", - onConsoleLog: () => false, + onConsoleLog: () => debuglog.enabled, testTimeout: 10000, }, publicDir: false, diff --git a/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts b/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts index edaf62fe76be..f37b6063cf7e 100644 --- a/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts +++ b/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts @@ -1,4 +1,5 @@ import assert from "node:assert"; +import util from "node:util"; import * as vite from "vite"; import { isNodeCompat } from "./node-js-compat"; import { INIT_PATH, UNKNOWN_HOST, VITE_DEV_METADATA_HEADER } from "./shared"; @@ -17,6 +18,7 @@ interface WebSocketContainer { } const webSocketUndefinedError = "The WebSocket is undefined"; +const debuglog = util.debuglog("@cloudflare:vite-plugin"); function createHotChannel( webSocketContainer: WebSocketContainer @@ -196,11 +198,13 @@ export function createCloudflareEnvironmentOptions( export function initRunners( resolvedPluginConfig: WorkersResolvedConfig, viteDevServer: vite.ViteDevServer, - miniflare: Miniflare + miniflare: Miniflare, + configId: string ): Promise | undefined { return Promise.all( Object.entries(resolvedPluginConfig.workers).map( async ([environmentName, workerConfig]) => { + debuglog(configId, "Initializing worker:", workerConfig.name); const worker = await miniflare.getWorker(workerConfig.name); return ( diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index 7a7f91c27014..61cb1984bed8 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -1,6 +1,8 @@ import assert from "node:assert"; +import { randomUUID } from "node:crypto"; import * as fsp from "node:fs/promises"; import * as path from "node:path"; +import util from "node:util"; import { generateContainerBuildId, getContainerIdsByImageTags, @@ -83,9 +85,10 @@ import type { Unstable_RawConfig } from "wrangler"; export type { PluginConfig } from "./plugin-config"; +const debuglog = util.debuglog("@cloudflare:vite-plugin"); + // this flag is used to show the workers configs warning only once let workersConfigsWarningShown = false; - let miniflare: Miniflare | undefined; /** @@ -335,37 +338,46 @@ if (import.meta.hot) { writeDeployConfig(resolvedPluginConfig, resolvedViteConfig); } }, - hotUpdate(options) { - assertIsNotPreview(resolvedPluginConfig); - - // Note that we must "resolve" the changed file since the path from Vite will not match Windows backslashes. - const changedFilePath = path.resolve(options.file); - - if ( - resolvedPluginConfig.configPaths.has(changedFilePath) || - hasLocalDevVarsFileChanged(resolvedPluginConfig, changedFilePath) || - hasAssetsConfigChanged( - resolvedPluginConfig, - resolvedViteConfig, - changedFilePath - ) - ) { - // It's OK for this to be called multiple times as Vite prevents concurrent execution - options.server.restart(); - return []; - } - }, // Vite `configureServer` Hook // see https://vite.dev/guide/api-plugin.html#configureserver async configureServer(viteDevServer) { assertIsNotPreview(resolvedPluginConfig); + // It is possible to get into a situation where the dev server is restarted by a config file change + // right in the middle of the Vite server and the supporting Workers being initialized. + // We use an abort controller to signal to the initialization code that it should stop if the config has changed. + const restartAbortController = new AbortController(); + // We use a `configId` to help debug how the config changes are triggering the restarts. + const configId = randomUUID(); + const inputInspectorPort = await getInputInspectorPortOption( resolvedPluginConfig, viteDevServer, miniflare ); + viteDevServer.watcher.addListener("change", (changedFilePath) => { + assertIsNotPreview(resolvedPluginConfig); + + if ( + resolvedPluginConfig.configPaths.has(changedFilePath) || + hasLocalDevVarsFileChanged(resolvedPluginConfig, changedFilePath) || + hasAssetsConfigChanged( + resolvedPluginConfig, + resolvedViteConfig, + changedFilePath + ) + ) { + debuglog( + configId, + "Config changed, restarting dev server and aborting previous setup: " + + changedFilePath + ); + restartAbortController.abort(); + viteDevServer.restart(); + } + }); + let containerBuildId: string | undefined; const entryWorkerConfig = getEntryWorkerConfig(resolvedPluginConfig); const hasDevContainers = @@ -386,18 +398,46 @@ if (import.meta.hot) { containerBuildId, }); + if (restartAbortController.signal.aborted) { + debuglog( + configId, + "Aborting setting up miniflare because config has changed." + ); + // The config has changes while this was still trying to setup the server. + // So just abort and allow the new server to be set up. + return; + } + if (!miniflare) { + debuglog(configId, "Creating new Miniflare instance"); miniflare = new Miniflare(miniflareDevOptions); } else { + debuglog(configId, "Updating the Miniflare instance"); await miniflare.setOptions(miniflareDevOptions); } let preMiddleware: vite.Connect.NextHandleFunction | undefined; + if (restartAbortController.signal.aborted) { + debuglog( + configId, + "Aborting setting up the dev server because config has changed." + ); + // The config has changes while this was still trying to setup the server. + // So just abort and allow the new server to be set up. + return; + } + if (resolvedPluginConfig.type === "workers") { assert(entryWorkerConfig, `No entry Worker config`); - await initRunners(resolvedPluginConfig, viteDevServer, miniflare); + debuglog(configId, "Initializing the Vite module runners"); + await initRunners( + resolvedPluginConfig, + viteDevServer, + miniflare, + configId + ); const entryWorkerName = entryWorkerConfig.name; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0819e5542ce8..5a70b767614a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2361,13 +2361,13 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: ^4.20250711.0 - version: 4.20250712.0 + version: 4.20250726.0 typescript: specifier: catalog:default version: 5.8.2 vite: specifier: catalog:vite-plugin - version: 7.0.0(@types/node@20.17.32)(jiti@2.4.2)(lightningcss@1.29.2) + version: 7.0.0(@types/node@20.19.9)(jiti@2.4.2)(lightningcss@1.29.2) wrangler: specifier: workspace:* version: link:../../../wrangler From a347c5e97520ac9a3c2f8e465df26c328d414003 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 28 Jul 2025 17:16:57 +0100 Subject: [PATCH 20/42] don't run playgrounds in parallel --- packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts index c8dad65bcfe1..34d2d5ff5b9c 100644 --- a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts +++ b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts @@ -9,6 +9,7 @@ export default defineConfig({ // Otherwise we occasionally get flakes where two tests are overwriting // the same output files. poolOptions: { forks: { singleFork: true } }, + fileParallelism: false, include: ["./**/__tests__/**/*.spec.[tj]s"], setupFiles: ["./vitest-setup.ts"], globalSetup: ["./vitest-global-setup.ts"], From 45231143495c2365f777de9a5c6e9f854a0acb74 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 28 Jul 2025 15:12:20 +0100 Subject: [PATCH 21/42] force runs of playground tests --- .github/workflows/test-and-check.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-and-check.yml b/.github/workflows/test-and-check.yml index b6023b3e1fd0..027e3f381f14 100644 --- a/.github/workflows/test-and-check.yml +++ b/.github/workflows/test-and-check.yml @@ -93,24 +93,24 @@ jobs: - os: macos-latest description: macOS node_version: 20.19.1 - filter: '--filter="./packages/*" --filter="./fixtures/*" --filter="./packages/vite-plugin-cloudflare/playground" --summarize' + filter: '--filter="./packages/vite-plugin-cloudflare/playground" --force' # needs to run on the amd runners to allow containers test to work in CI - os: ubuntu-24.04 description: Linux node_version: 20.19.1 # ./tools _only_ runs here because they're only intended to run in CI # Browser rendering is disabled here because of https://pptr.dev/troubleshooting#issues-with-apparmor-on-ubuntu - filter: '--filter="./tools" --filter="./packages/*" --filter="./fixtures/*" --filter="./packages/vite-plugin-cloudflare/playground" --filter="!./fixtures/browser-rendering"' + filter: '--filter="./packages/vite-plugin-cloudflare/playground" --force' - os: windows-latest description: Windows node_version: 20.19.1 - filter: '--filter="./packages/*" --filter="./fixtures/*" --filter="./packages/vite-plugin-cloudflare/playground"' + filter: '--filter="./packages/vite-plugin-cloudflare/playground" --force' # needs to run on the amd runners to allow containers test to work in CI - os: ubuntu-24.04 description: v22, Linux node_version: 22 # Browser rendering is disabled here because of https://pptr.dev/troubleshooting#issues-with-apparmor-on-ubuntu - filter: '--filter="./packages/*" --filter="./fixtures/*" --filter="./packages/vite-plugin-cloudflare/playground" --filter="!./packages/kv-asset-handler" --filter="!./fixtures/browser-rendering"' + filter: '--filter="./packages/vite-plugin-cloudflare/playground" --force' # Skipped until we upgrade to undici v7, because of https://github.com/nodejs/undici/issues/4285 # - os: ubuntu-24.04-arm # label: v24, Linux From 1beee4cf927bfbf06a027dc51a7b553fc2278f69 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 28 Jul 2025 17:36:36 +0100 Subject: [PATCH 22/42] log configid --- .../src/cloudflare-environment.ts | 6 ++++-- .../src/runner-worker/index.ts | 11 ++++++++--- .../src/runner-worker/module-runner.ts | 12 ++++++++++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts b/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts index f37b6063cf7e..3ff1d885679d 100644 --- a/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts +++ b/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts @@ -90,7 +90,8 @@ export class CloudflareDevEnvironment extends vite.DevEnvironment { async initRunner( worker: ReplaceWorkersTypes, - workerConfig: WorkerConfig + workerConfig: WorkerConfig, + configId: string ) { this.#worker = worker; @@ -100,6 +101,7 @@ export class CloudflareDevEnvironment extends vite.DevEnvironment { headers: { [VITE_DEV_METADATA_HEADER]: JSON.stringify({ entryPath: workerConfig.main, + configId, }), upgrade: "websocket", }, @@ -211,7 +213,7 @@ export function initRunners( viteDevServer.environments[ environmentName ] as CloudflareDevEnvironment - ).initRunner(worker, workerConfig); + ).initRunner(worker, workerConfig, configId); } ) ); diff --git a/packages/vite-plugin-cloudflare/src/runner-worker/index.ts b/packages/vite-plugin-cloudflare/src/runner-worker/index.ts index 01ef3db57178..900934de28d8 100644 --- a/packages/vite-plugin-cloudflare/src/runner-worker/index.ts +++ b/packages/vite-plugin-cloudflare/src/runner-worker/index.ts @@ -132,6 +132,7 @@ export function createWorkerEntrypointWrapper( entrypoint: string ): WorkerEntrypointConstructor { class Wrapper extends WorkerEntrypoint { + configId?: string; constructor(ctx: ExecutionContext, env: WrapperEnv) { super(ctx, env); @@ -176,7 +177,11 @@ export function createWorkerEntrypointWrapper( entryPath = viteDevMetadata.entryPath; const { 0: client, 1: server } = new WebSocketPair(); webSocket = client; - await createModuleRunner(this.env, server); + await createModuleRunner( + this.env, + server, + viteDevMetadata.configId + ); } catch (e) { return new Response( e instanceof Error ? e.message : JSON.stringify(e), @@ -406,7 +411,7 @@ function getViteDevMetadata(request: Request) { ); } - const { entryPath } = parsedViteDevMetadataHeader; + const { entryPath, configId } = parsedViteDevMetadataHeader; if (entryPath === undefined) { throw new Error( @@ -414,5 +419,5 @@ function getViteDevMetadata(request: Request) { ); } - return { entryPath }; + return { entryPath, configId }; } diff --git a/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts b/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts index e15e9e342861..e154b11cdc54 100644 --- a/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts +++ b/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts @@ -7,13 +7,20 @@ import { stripInternalEnv } from "./env"; import type { WrapperEnv } from "./env"; let moduleRunner: ModuleRunner; +let oldConfigId: string | undefined; export async function createModuleRunner( env: WrapperEnv, - webSocket: WebSocket + webSocket: WebSocket, + configId?: string ) { if (moduleRunner) { - throw new Error("Runner already initialized"); + throw new Error( + "Runner already initialized; old configId: " + + oldConfigId + + ", new configId: " + + configId + ); } const transport = createWebSocketModuleRunnerTransport({ @@ -24,6 +31,7 @@ export async function createModuleRunner( }, }); + oldConfigId = configId; moduleRunner = new ModuleRunner( { sourcemapInterceptor: "prepareStackTrace", From b0b9655c41a0e0026f92932d6c6f322b456d2e49 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 28 Jul 2025 17:48:41 +0100 Subject: [PATCH 23/42] remove watchers --- packages/vite-plugin-cloudflare/src/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index 61cb1984bed8..4064d8b5282f 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -356,7 +356,7 @@ if (import.meta.hot) { miniflare ); - viteDevServer.watcher.addListener("change", (changedFilePath) => { + viteDevServer.watcher.addListener("change", async (changedFilePath) => { assertIsNotPreview(resolvedPluginConfig); if ( @@ -374,7 +374,8 @@ if (import.meta.hot) { changedFilePath ); restartAbortController.abort(); - viteDevServer.restart(); + await viteDevServer.watcher.close(); + await viteDevServer.restart(); } }); From 35cb6bfe14b3ab81bea342c48a9ef19d82506ad3 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 28 Jul 2025 17:49:00 +0100 Subject: [PATCH 24/42] wait for miniflare to be ready before setting options --- packages/vite-plugin-cloudflare/src/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index 4064d8b5282f..94fa91441cd5 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -413,8 +413,13 @@ if (import.meta.hot) { debuglog(configId, "Creating new Miniflare instance"); miniflare = new Miniflare(miniflareDevOptions); } else { + debuglog(configId, "Waiting for Miniflare to be ready before update"); + await miniflare.ready; debuglog(configId, "Updating the Miniflare instance"); await miniflare.setOptions(miniflareDevOptions); + debuglog(configId, "Waiting for Miniflare to be ready after update"); + await miniflare.ready; + debuglog(configId, "Miniflare is ready"); } let preMiddleware: vite.Connect.NextHandleFunction | undefined; From bf5581e42859c0e4455b466e5b869a3598ec378f Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 28 Jul 2025 21:30:33 +0100 Subject: [PATCH 25/42] dispose vite server between playground tests --- .../vite-plugin-cloudflare/playground/vitest-setup.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/vite-plugin-cloudflare/playground/vitest-setup.ts b/packages/vite-plugin-cloudflare/playground/vitest-setup.ts index cc8736bc1beb..c7df30235a80 100644 --- a/packages/vite-plugin-cloudflare/playground/vitest-setup.ts +++ b/packages/vite-plugin-cloudflare/playground/vitest-setup.ts @@ -17,6 +17,7 @@ import type { InlineConfig, Logger, PluginOption, + PreviewServer, ResolvedConfig, UserConfig, ViteDevServer, @@ -31,7 +32,7 @@ export const isWindows = process.platform === "win32"; export const isCINonLinux = process.platform !== "linux" && process.env.CI === "true"; -let server: ViteDevServer | http.Server; +let server: ViteDevServer | http.Server | PreviewServer; /** * Vite Dev Server when testing serve @@ -160,7 +161,7 @@ beforeAll(async (s) => { viteTestUrl = mod.viteTestUrl ?? viteTestUrl; } } else { - await startDefaultServe(); + server = await startDefaultServe(); } } } catch (e) { @@ -252,7 +253,7 @@ export async function loadConfig(configEnv: ConfigEnv) { } export async function startDefaultServe(): Promise< - ViteDevServer | http.Server + ViteDevServer | http.Server | PreviewServer > { setupConsoleWarnCollector(serverLogs.warns); @@ -302,6 +303,7 @@ export async function startDefaultServe(): Promise< if (previewServer.config.base === "/") { viteTestUrl = viteTestUrl.replace(/\/$/, ""); } + server = previewServer; await page.goto(viteTestUrl); } return server; From 2a3be8c3fcc5192365a847a94fcb23464a005894 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Tue, 29 Jul 2025 09:41:11 +0100 Subject: [PATCH 26/42] More logs on mockfile changes --- .../vite-plugin-cloudflare/playground/__test-utils__/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts b/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts index 7fd42f124600..733676a2d943 100644 --- a/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts +++ b/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts @@ -14,7 +14,9 @@ export function mockFileChange( ) { const originalContent = fs.readFileSync(filePath, "utf-8"); onTestFinished(() => { + console.log("Restoring file change for", filePath); fs.writeFileSync(filePath, originalContent); }); + console.log("Mocking file change for", filePath); fs.writeFileSync(filePath, mutateFn(originalContent)); } From bc34d6a26476a8ee3037c3b5794b3f209c95c2ea Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Tue, 29 Jul 2025 10:18:19 +0100 Subject: [PATCH 27/42] handle internal body reading errors in miniflare When step-through debugging you can often get stuck on this bit of code, where there is an unhandled rejection in the body reading code. It is not apparent in real life and has no effect outside of debugging. --- packages/miniflare/src/index.ts | 113 +++++++++++++++++--------------- 1 file changed, 61 insertions(+), 52 deletions(-) diff --git a/packages/miniflare/src/index.ts b/packages/miniflare/src/index.ts index cc80774fdc95..3153bd4bbc76 100644 --- a/packages/miniflare/src/index.ts +++ b/packages/miniflare/src/index.ts @@ -776,56 +776,6 @@ export function _transformsForContentEncodingAndContentType( return encoders; } -async function writeResponse(response: Response, res: http.ServerResponse) { - // Convert headers into Node-friendly format - const headers: http.OutgoingHttpHeaders = {}; - for (const entry of response.headers) { - const key = entry[0].toLowerCase(); - const value = entry[1]; - if (key === "set-cookie") { - headers[key] = response.headers.getSetCookie(); - } else { - headers[key] = value; - } - } - - // If a `Content-Encoding` header is set, we'll need to encode the body - // (likely only set by custom service bindings) - const encoding = headers["content-encoding"]?.toString(); - const type = headers["content-type"]?.toString(); - const encoders = _transformsForContentEncodingAndContentType(encoding, type); - if (encoders.length > 0) { - // `Content-Length` if set, will be wrong as it's for the decoded length - delete headers["content-length"]; - } - - res.writeHead(response.status, response.statusText, headers); - - // `initialStream` is the stream we'll write the response to. It - // should end up as the first encoder, piping to the next encoder, - // and finally piping to the response: - // - // encoders[0] (initialStream) -> encoders[1] -> res - // - // Not using `pipeline(passThrough, ...encoders, res)` here as that - // gives a premature close error with server sent events. This also - // avoids creating an extra stream even when we're not encoding. - let initialStream: Writable = res; - for (let i = encoders.length - 1; i >= 0; i--) { - encoders[i].pipe(initialStream); - initialStream = encoders[i]; - } - - // Response body may be null if empty - if (response.body) { - for await (const chunk of response.body) { - if (chunk) initialStream.write(chunk); - } - } - - initialStream.end(); -} - function safeReadableStreamFrom(iterable: AsyncIterable) { // Adapted from `undici`, catches errors from `next()` to avoid unhandled // rejections from aborted request body streams: @@ -1344,7 +1294,7 @@ export class Miniflare { res.writeHead(404); res.end(); } else { - await writeResponse(response, res); + await this.#writeResponse(response, res); } } @@ -1402,7 +1352,7 @@ export class Miniflare { } // Otherwise, send the response as is (e.g. unauthorised) - await writeResponse(response, res); + await this.#writeResponse(response, res); }; #handleLoopbackConnect = async ( @@ -1508,6 +1458,65 @@ export class Miniflare { }); }; + async #writeResponse(response: Response, res: http.ServerResponse) { + // Convert headers into Node-friendly format + const headers: http.OutgoingHttpHeaders = {}; + for (const entry of response.headers) { + const key = entry[0].toLowerCase(); + const value = entry[1]; + if (key === "set-cookie") { + headers[key] = response.headers.getSetCookie(); + } else { + headers[key] = value; + } + } + + // If a `Content-Encoding` header is set, we'll need to encode the body + // (likely only set by custom service bindings) + const encoding = headers["content-encoding"]?.toString(); + const type = headers["content-type"]?.toString(); + const encoders = _transformsForContentEncodingAndContentType( + encoding, + type + ); + if (encoders.length > 0) { + // `Content-Length` if set, will be wrong as it's for the decoded length + delete headers["content-length"]; + } + + res.writeHead(response.status, response.statusText, headers); + + // `initialStream` is the stream we'll write the response to. It + // should end up as the first encoder, piping to the next encoder, + // and finally piping to the response: + // + // encoders[0] (initialStream) -> encoders[1] -> res + // + // Not using `pipeline(passThrough, ...encoders, res)` here as that + // gives a premature close error with server sent events. This also + // avoids creating an extra stream even when we're not encoding. + let initialStream: Writable = res; + for (let i = encoders.length - 1; i >= 0; i--) { + encoders[i].pipe(initialStream); + initialStream = encoders[i]; + } + + // Response body may be null if empty + if (response.body) { + try { + for await (const chunk of response.body) { + if (chunk) initialStream.write(chunk); + } + } catch (error) { + this.#log.debug( + `Error writing response body, closing response early: ${error}` + ); + } + } + + initialStream.end(); + } + async #getLoopbackPort(): Promise { // This function must be run with `#runtimeMutex` held From ad2035278d1032b1ada13a9d454fcaaaa0648a95 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Tue, 29 Jul 2025 09:41:31 +0100 Subject: [PATCH 28/42] test updates - use mockfile in config-changes test - each test in this file expects a starting condition but needs to wait for Vite to be ready since it might be rebooting. --- .../interactive-dev-tests/tests/index.test.ts | 2 +- .../pages-workerjs-app/tests/index.test.ts | 4 +- .../playground/__test-utils__/responses.ts | 7 +- .../__tests__/config-changes.spec.ts | 129 ++++++++---------- .../__tests__/dev-vars-loading.spec.ts | 27 ++-- .../dev-vars/__tests__/vars-changes.spec.ts | 49 ++++--- .../dev-vars-loading.spec.ts | 16 ++- .../with-specified-env/vars-changes.spec.ts | 80 ++++------- .../dot-env/__tests__/vars-changes.spec.ts | 37 ++--- .../__tests__/worker-als/als.spec.ts | 14 +- .../__tests__/worker-basic/basic.spec.ts | 10 +- .../worker-cross-env/cross-env.spec.ts | 10 +- .../__tests__/worker-crypto/crypto.spec.ts | 39 +++--- .../worker-postgres/postgres.spec.ts | 24 +++- .../process.spec.ts | 10 +- .../__tests__/worker-process/process.spec.ts | 9 +- .../__tests__/worker-random/random.spec.ts | 21 +-- .../resolve-externals.spec.ts | 16 ++- .../worker-warnings/warnings.spec.ts | 12 +- .../playground/vitest-setup.ts | 4 +- .../playground/vitest.config.e2e.ts | 2 +- .../worker/__tests__/worker.spec.ts | 16 ++- 22 files changed, 286 insertions(+), 252 deletions(-) diff --git a/fixtures/interactive-dev-tests/tests/index.test.ts b/fixtures/interactive-dev-tests/tests/index.test.ts index 341ac2d87477..5bf71077114b 100644 --- a/fixtures/interactive-dev-tests/tests/index.test.ts +++ b/fixtures/interactive-dev-tests/tests/index.test.ts @@ -719,7 +719,7 @@ baseDescribe.skipIf(process.platform !== "linux" && process.env.CI === "true")( await new Promise((resolve) => { wrangler.pty.onExit(() => resolve()); }); - vi.waitFor(() => { + await vi.waitFor(() => { const remainingIds = getContainerIds(); expect(remainingIds.length).toBe(0); }); diff --git a/fixtures/pages-workerjs-app/tests/index.test.ts b/fixtures/pages-workerjs-app/tests/index.test.ts index 61d9d87582e5..452b05eb7d46 100644 --- a/fixtures/pages-workerjs-app/tests/index.test.ts +++ b/fixtures/pages-workerjs-app/tests/index.test.ts @@ -83,7 +83,7 @@ describe("Pages _worker.js", () => { "--inspector-port=0", "--compatibility-date=2025-07-15", ]); - vi.waitFor( + await vi.waitFor( () => { expect(getOutput()).toContain("Ready on"); }, @@ -129,7 +129,7 @@ describe("Pages _worker.js", () => { "--port=0", "--inspector-port=0", ]); - vi.waitFor( + await vi.waitFor( () => { expect(getOutput()).toContain("Ready on"); }, diff --git a/packages/vite-plugin-cloudflare/playground/__test-utils__/responses.ts b/packages/vite-plugin-cloudflare/playground/__test-utils__/responses.ts index e0453aad190b..9fcda7de34ea 100644 --- a/packages/vite-plugin-cloudflare/playground/__test-utils__/responses.ts +++ b/packages/vite-plugin-cloudflare/playground/__test-utils__/responses.ts @@ -1,5 +1,7 @@ import { page, viteTestUrl } from "./index"; +export const WAIT_FOR_OPTIONS = { timeout: 5_000, interval: 500 }; + export async function getTextResponse(path = "/"): Promise { const response = await getResponse(path); return response.text(); @@ -7,19 +9,18 @@ export async function getTextResponse(path = "/"): Promise { export async function getJsonResponse( path = "/" -): Promise> { +): Promise | Array> { const response = await getResponse(path); const text = await response.text(); try { return JSON.parse(text); - } catch (e) { + } catch { throw new Error("Invalid JSON response:\n" + text); } } export async function getResponse(path = "/") { const url = `${viteTestUrl}${path}`; - const response = page.waitForResponse(url); await page.goto(url); return response; diff --git a/packages/vite-plugin-cloudflare/playground/config-changes/__tests__/config-changes.spec.ts b/packages/vite-plugin-cloudflare/playground/config-changes/__tests__/config-changes.spec.ts index a794cbc80f3f..ea99764e67ed 100644 --- a/packages/vite-plugin-cloudflare/playground/config-changes/__tests__/config-changes.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/config-changes/__tests__/config-changes.spec.ts @@ -1,84 +1,73 @@ -import * as fs from "node:fs"; import * as path from "node:path"; -import { expect, test, vi } from "vitest"; -import { getTextResponse, isBuild, serverLogs } from "../../__test-utils__"; +import { describe, expect, test, vi } from "vitest"; +import { + getTextResponse, + isBuild, + mockFileChange, + serverLogs, + WAIT_FOR_OPTIONS, +} from "../../__test-utils__"; -test.runIf(!isBuild)( - "successfully updates when a var is updated in the Worker config", - async ({ onTestFinished }) => { - const workerConfigPath = path.join(__dirname, "../wrangler.json"); - const originalWorkerConfig = fs.readFileSync(workerConfigPath, "utf-8"); - - onTestFinished(async () => { - fs.writeFileSync(workerConfigPath, originalWorkerConfig); - // We need to ensure that the original config is restored before the next test runs +describe("config-changes", () => { + test.runIf(!isBuild)( + "successfully updates when a var is updated in the Worker config", + async () => { await vi.waitFor( - async () => { - const revertedResponse = await getTextResponse(); - expect(revertedResponse).toContain('The value of MY_VAR is "one"'); - }, - { timeout: 5000 } + async () => + expect(await getTextResponse()).toContain( + 'The value of MY_VAR is "one"' + ), + WAIT_FOR_OPTIONS ); - }); - - const originalResponse = await getTextResponse(); - expect(originalResponse).toContain('The value of MY_VAR is "one"'); - const updatedWorkerConfig = JSON.stringify({ - ...JSON.parse(originalWorkerConfig), - vars: { - MY_VAR: "two", - }, - }); - fs.writeFileSync(workerConfigPath, updatedWorkerConfig); - await vi.waitFor( - async () => { - const updatedResponse = await getTextResponse(); - expect(updatedResponse).toContain('The value of MY_VAR is "two"'); - }, - { timeout: 5000 } - ); - } -); + mockFileChange(path.join(__dirname, "../wrangler.json"), (content) => + JSON.stringify({ + ...JSON.parse(content), + vars: { + MY_VAR: "two", + }, + }) + ); -test.runIf(!isBuild)( - "reports errors in updates to the Worker config", - async ({ onTestFinished }) => { - const workerConfigPath = path.join(__dirname, "../wrangler.json"); - const originalWorkerConfig = fs.readFileSync(workerConfigPath, "utf-8"); + await vi.waitFor( + async () => + expect(await getTextResponse()).toContain( + 'The value of MY_VAR is "two"' + ), + WAIT_FOR_OPTIONS + ); + } + ); - onTestFinished(async () => { - fs.writeFileSync(workerConfigPath, originalWorkerConfig); - // We need to ensure that the original config is restored before the next test runs + test.runIf(!isBuild)( + "reports errors in updates to the Worker config", + async () => { await vi.waitFor( - async () => { - const revertedResponse = await getTextResponse(); - expect(revertedResponse).toContain('The value of MY_VAR is "one"'); - }, - { timeout: 5000 } + async () => + expect(await getTextResponse()).toContain( + 'The value of MY_VAR is "one"' + ), + WAIT_FOR_OPTIONS ); - }); - const originalResponse = await getTextResponse(); - expect(originalResponse).toContain('The value of MY_VAR is "one"'); + mockFileChange(path.join(__dirname, "../wrangler.json"), (content) => + JSON.stringify({ + ...JSON.parse(content), + main: "./src/non-existing-file.ts", + vars: { + MY_VAR: "two", + }, + }) + ); - const updatedWorkerConfig = JSON.stringify({ - ...JSON.parse(originalWorkerConfig), - main: "./src/non-existing-file.ts", - vars: { - MY_VAR: "two", - }, - }); - fs.writeFileSync(workerConfigPath, updatedWorkerConfig); - await vi.waitFor( - async () => { - const newResponse = await getTextResponse(); + await vi.waitFor(async () => { expect(serverLogs.errors.join()).toMatch( /.*The provided Wrangler config main field .+? doesn't point to an existing file.*/ ); - expect(newResponse).toContain('The value of MY_VAR is "one"'); - }, - { timeout: 5000 } - ); - } -); + expect(await getTextResponse()).toContain( + 'The value of MY_VAR is "one"' + ); + }, WAIT_FOR_OPTIONS); + } + ); +}); diff --git a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/dev-vars-loading.spec.ts b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/dev-vars-loading.spec.ts index 270ca6870aa2..d4ee32f28971 100644 --- a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/dev-vars-loading.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/dev-vars-loading.spec.ts @@ -1,15 +1,24 @@ import fs from "node:fs"; -import { describe, expect, test } from "vitest"; -import { getJsonResponse, isBuild, testDir } from "../../__test-utils__"; +import { describe, expect, test, vi } from "vitest"; +import { + getJsonResponse, + isBuild, + testDir, + WAIT_FOR_OPTIONS, +} from "../../__test-utils__"; test("reading variables from a standard .dev.vars file", async () => { - expect(await getJsonResponse()).toEqual({ - "variables present in .dev.vars": { - MY_DEV_VAR_A: "my .dev.vars variable A", - MY_DEV_VAR_B: "my .dev.vars variable B", - MY_DEV_VAR_C: "my .dev.vars variable C", - }, - }); + await vi.waitFor( + async () => + expect(await getJsonResponse()).toEqual({ + "variables present in .dev.vars": { + MY_DEV_VAR_A: "my .dev.vars variable A", + MY_DEV_VAR_B: "my .dev.vars variable B", + MY_DEV_VAR_C: "my .dev.vars variable C", + }, + }), + WAIT_FOR_OPTIONS + ); }); describe.runIf(isBuild)("build output files", () => { diff --git a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/vars-changes.spec.ts b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/vars-changes.spec.ts index ef43666dda59..dfdfefdd79c5 100644 --- a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/vars-changes.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/vars-changes.spec.ts @@ -1,18 +1,26 @@ import * as path from "node:path"; import { expect, test, vi } from "vitest"; -import { getJsonResponse, isBuild, mockFileChange } from "../../__test-utils__"; +import { + getJsonResponse, + isBuild, + mockFileChange, + WAIT_FOR_OPTIONS, +} from "../../__test-utils__"; test.runIf(!isBuild)( "successfully updates when a var is updated in a .dev.vars file", async () => { - const originalResponse = await getJsonResponse(); - expect(originalResponse).toEqual({ - "variables present in .dev.vars": { - MY_DEV_VAR_A: "my .dev.vars variable A", - MY_DEV_VAR_B: "my .dev.vars variable B", - MY_DEV_VAR_C: "my .dev.vars variable C", - }, - }); + await vi.waitFor( + async () => + expect(await getJsonResponse()).toEqual({ + "variables present in .dev.vars": { + MY_DEV_VAR_A: "my .dev.vars variable A", + MY_DEV_VAR_B: "my .dev.vars variable B", + MY_DEV_VAR_C: "my .dev.vars variable C", + }, + }), + WAIT_FOR_OPTIONS + ); mockFileChange(path.join(__dirname, "../.dev.vars"), (content) => content.replace( @@ -21,18 +29,15 @@ test.runIf(!isBuild)( ) ); - await vi.waitFor( - async () => { - const updatedResponse = await getJsonResponse(); - expect(updatedResponse).toEqual({ - "variables present in .dev.vars": { - MY_DEV_VAR_A: "my .dev.vars UPDATED variable A", - MY_DEV_VAR_B: "my .dev.vars UPDATED variable B", - MY_DEV_VAR_C: "my .dev.vars UPDATED variable C", - }, - }); - }, - { timeout: 5000 } - ); + await vi.waitFor(async () => { + const updatedResponse = await getJsonResponse(); + expect(updatedResponse).toEqual({ + "variables present in .dev.vars": { + MY_DEV_VAR_A: "my .dev.vars UPDATED variable A", + MY_DEV_VAR_B: "my .dev.vars UPDATED variable B", + MY_DEV_VAR_C: "my .dev.vars UPDATED variable C", + }, + }); + }, WAIT_FOR_OPTIONS); } ); diff --git a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/dev-vars-loading.spec.ts b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/dev-vars-loading.spec.ts index 9dc8216fc048..fc0de86ac6ce 100644 --- a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/dev-vars-loading.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/dev-vars-loading.spec.ts @@ -1,14 +1,16 @@ import fs from "node:fs"; -import { describe, expect, test } from "vitest"; +import { describe, expect, test, vi } from "vitest"; import { getJsonResponse, isBuild, testDir } from "../../../__test-utils__"; test("reading variables from a staging .dev.vars file", async () => { - expect(await getJsonResponse()).toEqual({ - "variables present in .dev.vars.staging": { - MY_DEV_VAR_A: "my .dev.vars staging variable A", - MY_DEV_VAR_B: "my .dev.vars staging variable B", - }, - }); + await vi.waitFor(async () => + expect(await getJsonResponse()).toEqual({ + "variables present in .dev.vars.staging": { + MY_DEV_VAR_A: "my .dev.vars staging variable A", + MY_DEV_VAR_B: "my .dev.vars staging variable B", + }, + }) + ); }); describe.runIf(isBuild)("build output files", () => { diff --git a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/vars-changes.spec.ts b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/vars-changes.spec.ts index ce42e6ae712b..0a72dc11f921 100644 --- a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/vars-changes.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/vars-changes.spec.ts @@ -1,61 +1,41 @@ -import * as fs from "node:fs"; import * as path from "node:path"; import { expect, test, vi } from "vitest"; -import { getJsonResponse, isBuild } from "../../../__test-utils__"; +import { + getJsonResponse, + isBuild, + mockFileChange, + WAIT_FOR_OPTIONS, +} from "../../../__test-utils__"; test.runIf(!isBuild)( "successfully updates when a var is updated in a .dev.vars.staging file", - async ({ onTestFinished }) => { - const dotDevDotVarsFilePath = path.join( - __dirname, - "../../.dev.vars.staging" - ); - const originalDotDevDotVars = fs.readFileSync( - dotDevDotVarsFilePath, - "utf-8" - ); - - onTestFinished(async () => { - fs.writeFileSync(dotDevDotVarsFilePath, originalDotDevDotVars); - // We need to ensure that the original config is restored before the next test runs - await vi.waitFor( - async () => { - expect(await getJsonResponse()).toEqual({ - "variables present in .dev.vars.staging": { - MY_DEV_VAR_A: "my .dev.vars staging variable A", - MY_DEV_VAR_B: "my .dev.vars staging variable B", - }, - }); - }, - { timeout: 5000 } - ); - }); - - const originalResponse = await getJsonResponse(); - expect(originalResponse).toEqual({ - "variables present in .dev.vars.staging": { - MY_DEV_VAR_A: "my .dev.vars staging variable A", - MY_DEV_VAR_B: "my .dev.vars staging variable B", - }, - }); - - const updatedDotDevDotVars = originalDotDevDotVars.replace( - /my \.dev\.vars staging variable/g, - "my .dev.vars UPDATED staging variable" - ); - - fs.writeFileSync(dotDevDotVarsFilePath, updatedDotDevDotVars); + async () => { await vi.waitFor( - async () => { - const updatedResponse = await getJsonResponse(); - expect(updatedResponse).toEqual({ + async () => + expect(await getJsonResponse()).toEqual({ "variables present in .dev.vars.staging": { - MY_DEV_VAR_A: "my .dev.vars UPDATED staging variable A", - MY_DEV_VAR_B: "my .dev.vars UPDATED staging variable B", + MY_DEV_VAR_A: "my .dev.vars staging variable A", + MY_DEV_VAR_B: "my .dev.vars staging variable B", }, - }); - }, - { timeout: 5000 } + }), + WAIT_FOR_OPTIONS + ); + + mockFileChange(path.join(__dirname, "../../.dev.vars.staging"), (content) => + content.replace( + /my \.dev\.vars staging variable/g, + "my .dev.vars UPDATED staging variable" + ) ); + + await vi.waitFor(async () => { + const updatedResponse = await getJsonResponse(); + expect(updatedResponse).toEqual({ + "variables present in .dev.vars.staging": { + MY_DEV_VAR_A: "my .dev.vars UPDATED staging variable A", + MY_DEV_VAR_B: "my .dev.vars UPDATED staging variable B", + }, + }); + }, WAIT_FOR_OPTIONS); } ); diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts index 5cde8dc04573..07042b22396b 100644 --- a/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/vars-changes.spec.ts @@ -1,36 +1,41 @@ import * as path from "node:path"; import { expect, test, vi } from "vitest"; -import { getJsonResponse, isBuild, mockFileChange } from "../../__test-utils__"; +import { + getJsonResponse, + isBuild, + mockFileChange, + WAIT_FOR_OPTIONS, +} from "../../__test-utils__"; test.runIf(!isBuild)( "successfully updates when a var is updated in a .env file", async () => { - const originalResponseContent = { - "variables loaded from .env": { - MY_DEV_VAR_A: "my .env variable A", - MY_DEV_VAR_B: "my .env variable B", - MY_DEV_VAR_C: "my .env variable C", // Note that unlike .dev.vars, we merge .env files - }, - }; - const originalResponse = await getJsonResponse(); - expect(originalResponse).toMatchObject(originalResponseContent); + await vi.waitFor( + async () => + expect(await getJsonResponse()).toEqual({ + "variables loaded from .env": { + MY_DEV_VAR_A: "my .env variable A", + MY_DEV_VAR_B: "my .env variable B", + MY_DEV_VAR_C: "my .env variable C", + }, + }), + WAIT_FOR_OPTIONS + ); mockFileChange(path.join(__dirname, "../.env"), (content) => content.replace(/my \.env/g, "my .env UPDATED") ); await vi.waitFor( - async () => { - const updatedResponse = await getJsonResponse(); - expect(updatedResponse).toEqual({ + async () => + expect(await getJsonResponse()).toEqual({ "variables loaded from .env": { MY_DEV_VAR_A: "my .env UPDATED variable A", MY_DEV_VAR_B: "my .env UPDATED variable B", MY_DEV_VAR_C: "my .env UPDATED variable C", // Note that unlike .dev.vars, we merge .env files }, - }); - }, - { timeout: 5000 } + }), + WAIT_FOR_OPTIONS ); } ); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-als/als.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-als/als.spec.ts index d8b1836b206c..1b4bc730ca9a 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-als/als.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-als/als.spec.ts @@ -1,9 +1,15 @@ -import { expect, test } from "vitest"; -import { getTextResponse, serverLogs } from "../../../__test-utils__"; +import { expect, test, vi } from "vitest"; +import { + getTextResponse, + serverLogs, + WAIT_FOR_OPTIONS, +} from "../../../__test-utils__"; test("supports Node.js ALS mode", async () => { - const result = await getTextResponse(); + await vi.waitFor( + async () => expect(await getTextResponse()).toEqual("OK!"), + WAIT_FOR_OPTIONS + ); // It won't log any node.js compat warnings expect(serverLogs.warns).toEqual([]); - expect(result).toEqual("OK!"); }); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-basic/basic.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-basic/basic.spec.ts index fd059d27d15d..0ab97a243fb9 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-basic/basic.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-basic/basic.spec.ts @@ -1,7 +1,9 @@ -import { expect, test } from "vitest"; -import { getTextResponse } from "../../../__test-utils__"; +import { expect, test, vi } from "vitest"; +import { getTextResponse, WAIT_FOR_OPTIONS } from "../../../__test-utils__"; test("basic nodejs properties", async () => { - const result = await getTextResponse(); - expect(result).toBe(`"OK!"`); + await vi.waitFor( + async () => expect(await getTextResponse()).toEqual(`"OK!"`), + WAIT_FOR_OPTIONS + ); }); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-cross-env/cross-env.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-cross-env/cross-env.spec.ts index 2d8bbcb996a2..1324cc5ecd8a 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-cross-env/cross-env.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-cross-env/cross-env.spec.ts @@ -1,7 +1,9 @@ -import { expect, test } from "vitest"; -import { getTextResponse } from "../../../__test-utils__"; +import { expect, test, vi } from "vitest"; +import { getTextResponse, WAIT_FOR_OPTIONS } from "../../../__test-utils__"; test("import unenv aliased 3rd party packages (e.g. cross-env)", async () => { - const result = await getTextResponse(); - expect(result).toBe(`"OK!"`); + await vi.waitFor( + async () => expect(await getTextResponse()).toBe(`"OK!"`), + WAIT_FOR_OPTIONS + ); }); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-crypto/crypto.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-crypto/crypto.spec.ts index 0746066a9239..b97d4fdd4ed9 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-crypto/crypto.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-crypto/crypto.spec.ts @@ -1,24 +1,25 @@ -import { expect, test } from "vitest"; +import { expect, test, vi } from "vitest"; import { getTextResponse } from "../../../__test-utils__"; test("crypto.X509Certificate is implemented", async () => { - const result = await getTextResponse(); - expect(result).toMatchInlineSnapshot(` - ""OK!": -----BEGIN CERTIFICATE----- - MIICZjCCAc+gAwIBAgIUOsv8Y+x40C+gdNuu40N50KpGUhEwDQYJKoZIhvcNAQEL - BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM - GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDA5MjAwOTA4MTNaFw0yNTA5 - MjAwOTA4MTNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw - HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEB - BQADgY0AMIGJAoGBALpJn3dUrNmZhZV02RbjZKTd5j3hpgTncF4lG4Y3sQA18k0l - 7pt6xpZuXYSFH7v2zTAxYy+uYyYwX2NZur48dZc76FSzIeuQdoTCkT0NacwFRTR5 - fEEqPvvB85ozYuyk8Bl3vSsonivOH3WftEDp9mjkHROQzS4wAZbIj7Cp+is/AgMB - AAGjUzBRMB0GA1UdDgQWBBSzFJSiPAw2tJOg8oUXrFBdqWI6zDAfBgNVHSMEGDAW - gBSzFJSiPAw2tJOg8oUXrFBdqWI6zDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 - DQEBCwUAA4GBACbto0+Ds40F7faRFFMwg5nPyh7gsiX+ZK3FYcrO3oxh5ejfzwow - DKOOje4Ncaw0rIkVpxacPyjg+wANuK2Nv/Z4CVAD3mneE4gwgRdn38q8IYN9AtSv - GzEf4UxiLBbUB6WRBgyVyquGfUMlKl/tnm4q0yeYQloYKSoHpGeHVJuN - -----END CERTIFICATE----- - " + await vi.waitFor(async () => { + expect(await getTextResponse()).toMatchInlineSnapshot(` + ""OK!": -----BEGIN CERTIFICATE----- + MIICZjCCAc+gAwIBAgIUOsv8Y+x40C+gdNuu40N50KpGUhEwDQYJKoZIhvcNAQEL + BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM + GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDA5MjAwOTA4MTNaFw0yNTA5 + MjAwOTA4MTNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw + HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEB + BQADgY0AMIGJAoGBALpJn3dUrNmZhZV02RbjZKTd5j3hpgTncF4lG4Y3sQA18k0l + 7pt6xpZuXYSFH7v2zTAxYy+uYyYwX2NZur48dZc76FSzIeuQdoTCkT0NacwFRTR5 + fEEqPvvB85ozYuyk8Bl3vSsonivOH3WftEDp9mjkHROQzS4wAZbIj7Cp+is/AgMB + AAGjUzBRMB0GA1UdDgQWBBSzFJSiPAw2tJOg8oUXrFBdqWI6zDAfBgNVHSMEGDAW + gBSzFJSiPAw2tJOg8oUXrFBdqWI6zDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 + DQEBCwUAA4GBACbto0+Ds40F7faRFFMwg5nPyh7gsiX+ZK3FYcrO3oxh5ejfzwow + DKOOje4Ncaw0rIkVpxacPyjg+wANuK2Nv/Z4CVAD3mneE4gwgRdn38q8IYN9AtSv + GzEf4UxiLBbUB6WRBgyVyquGfUMlKl/tnm4q0yeYQloYKSoHpGeHVJuN + -----END CERTIFICATE----- + " `); + }); }); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-postgres/postgres.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-postgres/postgres.spec.ts index 3a9fe9dca186..93e9f6ec2d7a 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-postgres/postgres.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-postgres/postgres.spec.ts @@ -1,9 +1,16 @@ -import { expect, test } from "vitest"; -import { getJsonResponse, getTextResponse } from "../../../__test-utils__"; +import { expect, test, vi } from "vitest"; +import { + getJsonResponse, + getTextResponse, + WAIT_FOR_OPTIONS, +} from "../../../__test-utils__"; test("should be able to create a pg Client", async () => { - const result = await getTextResponse(); - expect(result).toMatchInlineSnapshot(`"hh-pgsql-public.ebi.ac.uk"`); + await vi.waitFor(async () => + expect(await getTextResponse()).toMatchInlineSnapshot( + `"hh-pgsql-public.ebi.ac.uk"` + ) + ); }); // Disabling actually querying the database in CI since we are getting this error: @@ -11,7 +18,12 @@ test("should be able to create a pg Client", async () => { test.runIf(!process.env.CI)( "should be able to use pg library to send a query", async () => { - const result = await getJsonResponse("/send-query"); - expect(result!.id).toEqual("21"); + await vi.waitFor( + async () => + expect(await getJsonResponse("/send-query")).toEqual( + expect.objectContaining({ id: "21" }) + ), + WAIT_FOR_OPTIONS + ); } ); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-process-populated-env/process.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-process-populated-env/process.spec.ts index 567ddeacd291..86a8d61733e6 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-process-populated-env/process.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-process-populated-env/process.spec.ts @@ -1,7 +1,9 @@ -import { expect, test } from "vitest"; -import { getTextResponse } from "../../../__test-utils__"; +import { expect, test, vi } from "vitest"; +import { getTextResponse, WAIT_FOR_OPTIONS } from "../../../__test-utils__"; test("should get a populated process.env object", async () => { - const result = await getTextResponse(); - expect(result).toBe(`OK!`); + await vi.waitFor( + async () => expect(await getTextResponse()).toBe(`OK!`), + WAIT_FOR_OPTIONS + ); }); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-process/process.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-process/process.spec.ts index 28405eb6cc48..ef876de3b472 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-process/process.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-process/process.spec.ts @@ -1,7 +1,8 @@ -import { expect, test } from "vitest"; -import { getTextResponse } from "../../../__test-utils__"; +import { expect, test, vi } from "vitest"; +import { getTextResponse, WAIT_FOR_OPTIONS } from "../../../__test-utils__"; test("should support process global", async () => { - const result = await getTextResponse(); - expect(result).toBe(`OK!`); + await vi.waitFor(async () => { + expect(await getTextResponse()).toBe(`OK!`); + }, WAIT_FOR_OPTIONS); }); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-random/random.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-random/random.spec.ts index 4e6789d2675d..8b9d55f7b258 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-random/random.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-random/random.spec.ts @@ -1,12 +1,15 @@ -import { expect, test } from "vitest"; -import { getJsonResponse } from "../../../__test-utils__"; +import { expect, test, vi } from "vitest"; +import { getJsonResponse, WAIT_FOR_OPTIONS } from "../../../__test-utils__"; test("should be able to call `getRandomValues()` bound to any object", async () => { - const result = await getJsonResponse(); - expect(result).toEqual([ - expect.any(String), - expect.any(String), - expect.any(String), - expect.any(String), - ]); + await vi.waitFor( + async () => + expect(await getJsonResponse()).toEqual([ + expect.any(String), + expect.any(String), + expect.any(String), + expect.any(String), + ]), + WAIT_FOR_OPTIONS + ); }); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-resolve-externals/resolve-externals.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-resolve-externals/resolve-externals.spec.ts index 64fb178a7bea..7508d844b3fa 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-resolve-externals/resolve-externals.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-resolve-externals/resolve-externals.spec.ts @@ -1,11 +1,17 @@ -import { expect, test } from "vitest"; -import { getTextResponse, isBuild, serverLogs } from "../../../__test-utils__"; +import { expect, test, vi } from "vitest"; +import { + getTextResponse, + isBuild, + serverLogs, + WAIT_FOR_OPTIONS, +} from "../../../__test-utils__"; test.skipIf(isBuild)( "resolves Node.js external when calling `resolveId` directly", async () => { - const result = await getTextResponse(); - expect(result).toBe(`OK!`); - expect(serverLogs.info.join()).toContain("__node:dns__"); + await vi.waitFor(async () => { + expect(await getTextResponse()).toBe(`OK!`); + expect(serverLogs.info.join()).toContain("__node:dns__"); + }, WAIT_FOR_OPTIONS); } ); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-warnings/warnings.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-warnings/warnings.spec.ts index 9e419376e4b7..52d2d9397087 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-warnings/warnings.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-warnings/warnings.spec.ts @@ -5,14 +5,16 @@ import { isBuild, serverLogs } from "../../../__test-utils__"; test.skipIf(isBuild)( "should display warnings if nodejs_compat is missing", async () => { - await vi.waitFor(async () => { - expect(serverLogs.warns.join("").replaceAll("\\", "/")).toContain( - dedent` + await vi.waitFor( + async () => + expect(serverLogs.warns.join("").replaceAll("\\", "/")).toContain( + dedent` Unexpected Node.js imports for environment "worker". Do you need to enable the "nodejs_compat" compatibility flag? Refer to https://developers.cloudflare.com/workers/runtime-apis/nodejs/ for more details. - "node:assert/strict" imported from "worker-warnings/index.ts" - "perf_hooks" imported from "worker-warnings/index.ts" ` - ); - }); + ), + { timeout: 5_000, interval: 500 } + ); } ); diff --git a/packages/vite-plugin-cloudflare/playground/vitest-setup.ts b/packages/vite-plugin-cloudflare/playground/vitest-setup.ts index c7df30235a80..bf4d2446244b 100644 --- a/packages/vite-plugin-cloudflare/playground/vitest-setup.ts +++ b/packages/vite-plugin-cloudflare/playground/vitest-setup.ts @@ -186,9 +186,7 @@ beforeAll(async (s) => { }; }, 15_000); -beforeEach(async () => { - await page.goto(viteTestUrl); -}); +beforeEach(() => page.goto(viteTestUrl)); export async function loadConfig(configEnv: ConfigEnv) { let config: UserConfig | null = null; diff --git a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts index 34d2d5ff5b9c..c1ed6a677fb1 100644 --- a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts +++ b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts @@ -15,7 +15,7 @@ export default defineConfig({ globalSetup: ["./vitest-global-setup.ts"], reporters: "dot", onConsoleLog: () => debuglog.enabled, - testTimeout: 10000, + testTimeout: 100_000, }, publicDir: false, }); diff --git a/packages/vite-plugin-cloudflare/playground/worker/__tests__/worker.spec.ts b/packages/vite-plugin-cloudflare/playground/worker/__tests__/worker.spec.ts index dccdd5558650..937c00e52f05 100644 --- a/packages/vite-plugin-cloudflare/playground/worker/__tests__/worker.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/worker/__tests__/worker.spec.ts @@ -7,10 +7,14 @@ import { rootDir, serverLogs, viteTestUrl, + WAIT_FOR_OPTIONS, } from "../../__test-utils__"; test("basic hello-world functionality", async () => { - expect(await getTextResponse()).toEqual("Hello World!"); + await vi.waitFor( + async () => expect(await getTextResponse()).toEqual("Hello World!"), + WAIT_FOR_OPTIONS + ); }); test("basic dev logging", async () => { @@ -21,8 +25,11 @@ test("basic dev logging", async () => { test("receives the original host as the `X-Forwarded-Host` header", async () => { const testUrl = new URL(viteTestUrl); - const response = await getTextResponse("/x-forwarded-host"); - expect(response).toBe(testUrl.host); + await vi.waitFor( + async () => + expect(await getTextResponse("/x-forwarded-host")).toEqual(testUrl.host), + WAIT_FOR_OPTIONS + ); }); test("does not cause unhandled rejection", async () => { @@ -32,12 +39,13 @@ test("does not cause unhandled rejection", async () => { test.runIf(!isBuild)( "updates using HMR code in Worker entry file", async () => { + // Touch the worker entry file to trigger a HMR update. const workerEntryPath = path.join(rootDir, "src", "index.ts"); const originalContent = fs.readFileSync(workerEntryPath, "utf-8"); fs.writeFileSync(workerEntryPath, originalContent); await vi.waitFor(() => { expect(serverLogs.info.join()).toContain("[vite] hot updated"); - }); + }, WAIT_FOR_OPTIONS); } ); From f52d4b180fb56564f048312b2e02968619e192f4 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Tue, 29 Jul 2025 21:00:42 +0100 Subject: [PATCH 29/42] don't run `page.goto()` in the setup file --- .../playground/hot-channel/__tests__/hot-channel.spec.ts | 4 +++- packages/vite-plugin-cloudflare/playground/vitest-setup.ts | 4 +--- .../playground/websockets/__tests__/websockets.spec.ts | 6 +++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/vite-plugin-cloudflare/playground/hot-channel/__tests__/hot-channel.spec.ts b/packages/vite-plugin-cloudflare/playground/hot-channel/__tests__/hot-channel.spec.ts index cd167dabedd5..6f57db94fec6 100644 --- a/packages/vite-plugin-cloudflare/playground/hot-channel/__tests__/hot-channel.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/hot-channel/__tests__/hot-channel.spec.ts @@ -1,10 +1,12 @@ import { expect, test } from "vitest"; -import { isBuild, serverLogs } from "../../__test-utils__"; +import { isBuild, page, serverLogs, viteTestUrl } from "../../__test-utils__"; test.runIf(!isBuild)("client receives custom events", async () => { + await page.goto(viteTestUrl); expect(serverLogs.info.join()).toContain("__server-event-data-received__"); }); test.runIf(!isBuild)("server receives custom events", async () => { + await page.goto(viteTestUrl); expect(serverLogs.info.join()).toContain("__client-event-data-received__"); }); diff --git a/packages/vite-plugin-cloudflare/playground/vitest-setup.ts b/packages/vite-plugin-cloudflare/playground/vitest-setup.ts index bf4d2446244b..d024266a633a 100644 --- a/packages/vite-plugin-cloudflare/playground/vitest-setup.ts +++ b/packages/vite-plugin-cloudflare/playground/vitest-setup.ts @@ -9,7 +9,7 @@ import { preview, Rollup, } from "vite"; -import { beforeAll, beforeEach, inject } from "vitest"; +import { beforeAll, inject } from "vitest"; import type * as http from "node:http"; import type { Browser, Page } from "playwright-chromium"; import type { @@ -186,8 +186,6 @@ beforeAll(async (s) => { }; }, 15_000); -beforeEach(() => page.goto(viteTestUrl)); - export async function loadConfig(configEnv: ConfigEnv) { let config: UserConfig | null = null; let cacheDir = "node_modules/.vite"; diff --git a/packages/vite-plugin-cloudflare/playground/websockets/__tests__/websockets.spec.ts b/packages/vite-plugin-cloudflare/playground/websockets/__tests__/websockets.spec.ts index 9806dd880a19..d26244f5596b 100644 --- a/packages/vite-plugin-cloudflare/playground/websockets/__tests__/websockets.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/websockets/__tests__/websockets.spec.ts @@ -1,7 +1,8 @@ import { expect, test, vi } from "vitest"; -import { page } from "../../__test-utils__"; +import { page, viteTestUrl } from "../../__test-utils__"; async function openWebSocket() { + await page.goto(viteTestUrl); const openButton = page.getByRole("button", { name: "Open WebSocket" }); const statusTextBefore = await page.textContent("h2"); expect(statusTextBefore).toBe("WebSocket closed"); @@ -15,6 +16,7 @@ async function openWebSocket() { test("opens WebSocket connection", openWebSocket); test("closes WebSocket connection", async () => { + await page.goto(viteTestUrl); await openWebSocket(); const closeButton = page.getByRole("button", { name: "Close WebSocket" }); const statusTextBefore = await page.textContent("h2"); @@ -27,6 +29,7 @@ test("closes WebSocket connection", async () => { }); test("sends and receives WebSocket string messages", async () => { + await page.goto(viteTestUrl); await openWebSocket(); const sendButton = page.getByRole("button", { name: "Send string" }); const messageTextBefore = await page.textContent("p"); @@ -41,6 +44,7 @@ test("sends and receives WebSocket string messages", async () => { }); test("sends and receives WebSocket ArrayBuffer messages", async () => { + await page.goto(viteTestUrl); await openWebSocket(); const sendButton = page.getByRole("button", { name: "Send ArrayBuffer" }); const messageTextBefore = await page.textContent("p"); From 3b62d4b8fdb92cd1e39763966de5836447c788c1 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Tue, 29 Jul 2025 21:20:19 +0100 Subject: [PATCH 30/42] restart fixes - only listen for one config change before restarting - abort extra restarts --- packages/vite-plugin-cloudflare/src/index.ts | 25 +++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index 94fa91441cd5..617b960bbc32 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -356,7 +356,7 @@ if (import.meta.hot) { miniflare ); - viteDevServer.watcher.addListener("change", async (changedFilePath) => { + viteDevServer.watcher.once("change", async (changedFilePath) => { assertIsNotPreview(resolvedPluginConfig); if ( @@ -368,14 +368,21 @@ if (import.meta.hot) { changedFilePath ) ) { - debuglog( - configId, - "Config changed, restarting dev server and aborting previous setup: " + - changedFilePath - ); - restartAbortController.abort(); - await viteDevServer.watcher.close(); - await viteDevServer.restart(); + debuglog(configId, "Config changed: " + changedFilePath); + if (!restartAbortController.signal.aborted) { + debuglog( + configId, + "Restarting dev server and aborting previous setup" + ); + restartAbortController.abort(); + await viteDevServer.watcher.close(); + await viteDevServer.restart(); + } else { + debuglog( + configId, + "Config changed but already aborted previous setup, ignoring." + ); + } } }); From 0777d99dcba643d7200c74a286811574e4f51559 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Tue, 29 Jul 2025 22:27:38 +0100 Subject: [PATCH 31/42] dispose of Miniflare instance when Vite is disposed --- packages/vite-plugin-cloudflare/src/index.ts | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index 617b960bbc32..ace1b5604362 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -107,6 +107,15 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] { let containerImageTagsSeen: Set | undefined; let runningContainerIds: Array; + // This is needed so that we can tell the difference between the Vite http server closing and restarting. + let previousServer: unknown; + let restartingServer = false; + function updateRestartingServerFlag(viteDevServer: unknown) { + restartingServer = + previousServer !== undefined && viteDevServer !== previousServer; + previousServer = viteDevServer; + } + return [ { name: "vite-plugin-cloudflare", @@ -341,6 +350,7 @@ if (import.meta.hot) { // Vite `configureServer` Hook // see https://vite.dev/guide/api-plugin.html#configureserver async configureServer(viteDevServer) { + updateRestartingServerFlag(viteDevServer); assertIsNotPreview(resolvedPluginConfig); // It is possible to get into a situation where the dev server is restarted by a config file change @@ -612,6 +622,7 @@ if (import.meta.hot) { // Vite `configurePreviewServer` Hook // see https://vite.dev/guide/api-plugin.html#configurepreviewserver async configurePreviewServer(vitePreviewServer) { + updateRestartingServerFlag(vitePreviewServer); assertIsPreview(resolvedPluginConfig); const inputInspectorPort = await getInputInspectorPortOption( @@ -705,6 +716,21 @@ if (import.meta.hot) { containerImageTagsSeen.clear(); runningContainerIds = []; } + + if (!restartingServer) { + debuglog("Disposing Miniflare instance"); + await miniflare?.dispose().catch((error) => { + console.error("Error disposing Miniflare instance:", error); + }); + miniflare = undefined; + } else { + debuglog( + "Vite is restarting so do not dispose of Miniflare instance" + ); + } + // Reset the flag so that if a `buildEnd` hook is called again before the next + // configureServer hook then we do dispose of miniflare correctly. + restartingServer = false; }, }, // Plugin to provide a fallback entry file From 6fd486190149247bc5f90564cbd73afaeed23c44 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Tue, 29 Jul 2025 22:37:35 +0100 Subject: [PATCH 32/42] log stack --- packages/vite-plugin-cloudflare/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index ace1b5604362..031588c95d0a 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -426,6 +426,8 @@ if (import.meta.hot) { return; } + debuglog(configId, new Error("").stack); + if (!miniflare) { debuglog(configId, "Creating new Miniflare instance"); miniflare = new Miniflare(miniflareDevOptions); From fe5d37504ae51df1f67c0f0fa34b3761dd375ee7 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 30 Jul 2025 08:12:47 +0100 Subject: [PATCH 33/42] more diagnostics --- packages/vite-plugin-cloudflare/src/index.ts | 36 +++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index 031588c95d0a..6bd36ae9c32b 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -107,14 +107,7 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] { let containerImageTagsSeen: Set | undefined; let runningContainerIds: Array; - // This is needed so that we can tell the difference between the Vite http server closing and restarting. - let previousServer: unknown; let restartingServer = false; - function updateRestartingServerFlag(viteDevServer: unknown) { - restartingServer = - previousServer !== undefined && viteDevServer !== previousServer; - previousServer = viteDevServer; - } return [ { @@ -350,7 +343,17 @@ if (import.meta.hot) { // Vite `configureServer` Hook // see https://vite.dev/guide/api-plugin.html#configureserver async configureServer(viteDevServer) { - updateRestartingServerFlag(viteDevServer); + const restartServer = viteDevServer.restart.bind(viteDevServer); + viteDevServer.restart = async () => { + try { + restartingServer = true; + debuglog(configId, "From server.restart(): Restarting server..."); + await restartServer(); + debuglog(configId, "From server.restart(): Restarted server..."); + } finally { + restartingServer = false; + } + }; assertIsNotPreview(resolvedPluginConfig); // It is possible to get into a situation where the dev server is restarted by a config file change @@ -426,7 +429,12 @@ if (import.meta.hot) { return; } - debuglog(configId, new Error("").stack); + debuglog( + configId, + new Error("").stack?.includes("restartServer") + ? "From stack trace: restarting server..." + : "From stack trace: creating new server..." + ); if (!miniflare) { debuglog(configId, "Creating new Miniflare instance"); @@ -624,7 +632,6 @@ if (import.meta.hot) { // Vite `configurePreviewServer` Hook // see https://vite.dev/guide/api-plugin.html#configurepreviewserver async configurePreviewServer(vitePreviewServer) { - updateRestartingServerFlag(vitePreviewServer); assertIsPreview(resolvedPluginConfig); const inputInspectorPort = await getInputInspectorPortOption( @@ -719,16 +726,13 @@ if (import.meta.hot) { runningContainerIds = []; } + debuglog("buildEnd:", restartingServer ? "restarted" : "disposing"); if (!restartingServer) { - debuglog("Disposing Miniflare instance"); + debuglog("buildEnd: disposing Miniflare instance"); await miniflare?.dispose().catch((error) => { - console.error("Error disposing Miniflare instance:", error); + debuglog("buildEnd: failed to dispose Miniflare instance:", error); }); miniflare = undefined; - } else { - debuglog( - "Vite is restarting so do not dispose of Miniflare instance" - ); } // Reset the flag so that if a `buildEnd` hook is called again before the next // configureServer hook then we do dispose of miniflare correctly. From 761bdfa568cb1d01599ef7c0f2b621644aeb3bbf Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 30 Jul 2025 08:39:58 +0100 Subject: [PATCH 34/42] fix lockfile --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5a70b767614a..0e735fc71cb1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2361,7 +2361,7 @@ importers: version: link:../../../workers-tsconfig '@cloudflare/workers-types': specifier: ^4.20250711.0 - version: 4.20250726.0 + version: 4.20250730.0 typescript: specifier: catalog:default version: 5.8.2 From e692a46d51f0b6613525e3e431a0d461ee91a004 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 30 Jul 2025 08:34:11 +0100 Subject: [PATCH 35/42] separate forks --- .../vite-plugin-cloudflare/playground/vitest.config.e2e.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts index c1ed6a677fb1..cb2dad9806ef 100644 --- a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts +++ b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts @@ -5,10 +5,8 @@ const debuglog = util.debuglog("@cloudflare:vite-plugin"); export default defineConfig({ test: { - // We run these tests in a single fork to avoid them running in parallel. - // Otherwise we occasionally get flakes where two tests are overwriting - // the same output files. - poolOptions: { forks: { singleFork: true } }, + // We run these tests one file at a time. + // Otherwise we occasionally get flakes where two playground variants are overwriting the same files. fileParallelism: false, include: ["./**/__tests__/**/*.spec.[tj]s"], setupFiles: ["./vitest-setup.ts"], From c51ba25e5edaaa2635a8e995e1a76334799f3a74 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 30 Jul 2025 09:38:09 +0100 Subject: [PATCH 36/42] final cleanups --- .../playground/__test-utils__/index.ts | 5 ++++ .../playground/__test-utils__/responses.ts | 1 + .../dev-vars-loading.spec.ts | 23 +++++++++++------- .../with-specified-env/vars-changes.spec.ts | 24 +++++++++---------- .../worker-postgres/postgres.spec.ts | 10 ++++---- .../worker-warnings/warnings.spec.ts | 4 ++-- .../playground/vitest.config.e2e.ts | 2 +- .../src/cloudflare-environment.ts | 2 ++ packages/vite-plugin-cloudflare/src/index.ts | 8 +++++-- .../src/runner-worker/index.ts | 1 + .../src/runner-worker/module-runner.ts | 1 + packages/wrangler/src/api/dev.ts | 2 +- 12 files changed, 52 insertions(+), 31 deletions(-) diff --git a/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts b/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts index 733676a2d943..246ba055a0af 100644 --- a/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts +++ b/packages/vite-plugin-cloudflare/playground/__test-utils__/index.ts @@ -8,8 +8,13 @@ export function failsIf(condition: boolean) { return condition ? test.fails : test; } +/** + * Makes a change to a file and restores it after the test is finished. + */ export function mockFileChange( + /** The path to the file to change */ filePath: string, + /** A function that modifies the original content of the file */ mutateFn: (originalContent: string) => string ) { const originalContent = fs.readFileSync(filePath, "utf-8"); diff --git a/packages/vite-plugin-cloudflare/playground/__test-utils__/responses.ts b/packages/vite-plugin-cloudflare/playground/__test-utils__/responses.ts index 9fcda7de34ea..c9d600ddcc2b 100644 --- a/packages/vite-plugin-cloudflare/playground/__test-utils__/responses.ts +++ b/packages/vite-plugin-cloudflare/playground/__test-utils__/responses.ts @@ -1,5 +1,6 @@ import { page, viteTestUrl } from "./index"; +/** Common options to use with `vi.waitFor()` */ export const WAIT_FOR_OPTIONS = { timeout: 5_000, interval: 500 }; export async function getTextResponse(path = "/"): Promise { diff --git a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/dev-vars-loading.spec.ts b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/dev-vars-loading.spec.ts index fc0de86ac6ce..e10fb0306491 100644 --- a/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/dev-vars-loading.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/dev-vars/__tests__/with-specified-env/dev-vars-loading.spec.ts @@ -1,15 +1,22 @@ import fs from "node:fs"; import { describe, expect, test, vi } from "vitest"; -import { getJsonResponse, isBuild, testDir } from "../../../__test-utils__"; +import { + getJsonResponse, + isBuild, + testDir, + WAIT_FOR_OPTIONS, +} from "../../../__test-utils__"; test("reading variables from a staging .dev.vars file", async () => { - await vi.waitFor(async () => - expect(await getJsonResponse()).toEqual({ - "variables present in .dev.vars.staging": { - MY_DEV_VAR_A: "my .dev.vars staging variable A", - MY_DEV_VAR_B: "my .dev.vars staging variable B", - }, - }) + await vi.waitFor( + async () => + expect(await getJsonResponse()).toEqual({ + "variables present in .dev.vars.staging": { + MY_DEV_VAR_A: "my .dev.vars staging variable A", + MY_DEV_VAR_B: "my .dev.vars staging variable B", + }, + }), + WAIT_FOR_OPTIONS ); }); diff --git a/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/vars-changes.spec.ts b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/vars-changes.spec.ts index db08078036da..6512a1b234e8 100644 --- a/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/vars-changes.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/dot-env/__tests__/with-specified-env/vars-changes.spec.ts @@ -4,6 +4,7 @@ import { getJsonResponse, isBuild, mockFileChange, + WAIT_FOR_OPTIONS, } from "../../../__test-utils__"; test.runIf(!isBuild)( @@ -26,18 +27,15 @@ test.runIf(!isBuild)( content.replace(/my \.env staging/g, "my .env UPDATED staging") ); - await vi.waitFor( - async () => { - const updatedResponse = await getJsonResponse(); - expect(updatedResponse).toEqual({ - "variables loaded from .env and .env.staging": { - MY_DEV_VAR_A: "my .env UPDATED staging variable A", - MY_DEV_VAR_B: "my .env UPDATED staging variable B", - MY_DEV_VAR_C: "my .env UPDATED variable C", // Note that unlike .dev.vars, we merge .env files - }, - }); - }, - { timeout: 5000 } - ); + await vi.waitFor(async () => { + const updatedResponse = await getJsonResponse(); + expect(updatedResponse).toEqual({ + "variables loaded from .env and .env.staging": { + MY_DEV_VAR_A: "my .env UPDATED staging variable A", + MY_DEV_VAR_B: "my .env UPDATED staging variable B", + MY_DEV_VAR_C: "my .env UPDATED variable C", // Note that unlike .dev.vars, we merge .env files + }, + }); + }, WAIT_FOR_OPTIONS); } ); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-postgres/postgres.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-postgres/postgres.spec.ts index 93e9f6ec2d7a..8de85e4ba881 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-postgres/postgres.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-postgres/postgres.spec.ts @@ -6,10 +6,12 @@ import { } from "../../../__test-utils__"; test("should be able to create a pg Client", async () => { - await vi.waitFor(async () => - expect(await getTextResponse()).toMatchInlineSnapshot( - `"hh-pgsql-public.ebi.ac.uk"` - ) + await vi.waitFor( + async () => + expect(await getTextResponse()).toMatchInlineSnapshot( + `"hh-pgsql-public.ebi.ac.uk"` + ), + WAIT_FOR_OPTIONS ); }); diff --git a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-warnings/warnings.spec.ts b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-warnings/warnings.spec.ts index 52d2d9397087..17c2ac8d0ed4 100644 --- a/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-warnings/warnings.spec.ts +++ b/packages/vite-plugin-cloudflare/playground/node-compat/__tests__/worker-warnings/warnings.spec.ts @@ -1,6 +1,6 @@ import dedent from "ts-dedent"; import { expect, test, vi } from "vitest"; -import { isBuild, serverLogs } from "../../../__test-utils__"; +import { isBuild, serverLogs, WAIT_FOR_OPTIONS } from "../../../__test-utils__"; test.skipIf(isBuild)( "should display warnings if nodejs_compat is missing", @@ -14,7 +14,7 @@ test.skipIf(isBuild)( - "perf_hooks" imported from "worker-warnings/index.ts" ` ), - { timeout: 5_000, interval: 500 } + WAIT_FOR_OPTIONS ); } ); diff --git a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts index cb2dad9806ef..3b76e50cb23e 100644 --- a/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts +++ b/packages/vite-plugin-cloudflare/playground/vitest.config.e2e.ts @@ -13,7 +13,7 @@ export default defineConfig({ globalSetup: ["./vitest-global-setup.ts"], reporters: "dot", onConsoleLog: () => debuglog.enabled, - testTimeout: 100_000, + testTimeout: 10000, }, publicDir: false, }); diff --git a/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts b/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts index 3ff1d885679d..09c88fc16111 100644 --- a/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts +++ b/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts @@ -91,6 +91,7 @@ export class CloudflareDevEnvironment extends vite.DevEnvironment { async initRunner( worker: ReplaceWorkersTypes, workerConfig: WorkerConfig, + /** A unique identifier used for debugging errors when config updates. */ configId: string ) { this.#worker = worker; @@ -201,6 +202,7 @@ export function initRunners( resolvedPluginConfig: WorkersResolvedConfig, viteDevServer: vite.ViteDevServer, miniflare: Miniflare, + /** A unique identifier used for debugging errors when config updates. */ configId: string ): Promise | undefined { return Promise.all( diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index 6bd36ae9c32b..72de2abcc252 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -107,6 +107,7 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] { let containerImageTagsSeen: Set | undefined; let runningContainerIds: Array; + /** Used to track whether hooks are being called because of a server restart or a server close event. */ let restartingServer = false; return [ @@ -343,6 +344,7 @@ if (import.meta.hot) { // Vite `configureServer` Hook // see https://vite.dev/guide/api-plugin.html#configureserver async configureServer(viteDevServer) { + // Patch the `server.restart` method to track whether the server is restarting or not. const restartServer = viteDevServer.restart.bind(viteDevServer); viteDevServer.restart = async () => { try { @@ -354,12 +356,14 @@ if (import.meta.hot) { restartingServer = false; } }; + assertIsNotPreview(resolvedPluginConfig); // It is possible to get into a situation where the dev server is restarted by a config file change // right in the middle of the Vite server and the supporting Workers being initialized. // We use an abort controller to signal to the initialization code that it should stop if the config has changed. const restartAbortController = new AbortController(); + // We use a `configId` to help debug how the config changes are triggering the restarts. const configId = randomUUID(); @@ -424,8 +428,8 @@ if (import.meta.hot) { configId, "Aborting setting up miniflare because config has changed." ); - // The config has changes while this was still trying to setup the server. - // So just abort and allow the new server to be set up. + // The config has changed while we were still trying to setup the server, + // so just abort and allow the new server to be set up instead. return; } diff --git a/packages/vite-plugin-cloudflare/src/runner-worker/index.ts b/packages/vite-plugin-cloudflare/src/runner-worker/index.ts index 900934de28d8..c47c88e8baf9 100644 --- a/packages/vite-plugin-cloudflare/src/runner-worker/index.ts +++ b/packages/vite-plugin-cloudflare/src/runner-worker/index.ts @@ -132,6 +132,7 @@ export function createWorkerEntrypointWrapper( entrypoint: string ): WorkerEntrypointConstructor { class Wrapper extends WorkerEntrypoint { + /** A unique identifier used for debugging errors when config updates. */ configId?: string; constructor(ctx: ExecutionContext, env: WrapperEnv) { super(ctx, env); diff --git a/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts b/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts index e154b11cdc54..ec99da0c3e44 100644 --- a/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts +++ b/packages/vite-plugin-cloudflare/src/runner-worker/module-runner.ts @@ -12,6 +12,7 @@ let oldConfigId: string | undefined; export async function createModuleRunner( env: WrapperEnv, webSocket: WebSocket, + /** A unique identifier used for debugging errors when config updates. */ configId?: string ) { if (moduleRunner) { diff --git a/packages/wrangler/src/api/dev.ts b/packages/wrangler/src/api/dev.ts index b972d249398e..9c500eb51937 100644 --- a/packages/wrangler/src/api/dev.ts +++ b/packages/wrangler/src/api/dev.ts @@ -15,7 +15,7 @@ import type { RequestInfo, RequestInit, Response } from "undici"; export interface Unstable_DevOptions { config?: string; // Path to .toml configuration file, relative to cwd env?: string; // Environment to use for operations, and for selecting .env and .dev.vars files - envFiles?: string[]; // Paths to .env file to load, relative to cwd + envFiles?: string[]; // Paths to .env files to load, relative to cwd ip?: string; // IP address to listen on port?: number; // Port to listen on bundle?: boolean; // Set to false to skip internal build steps and directly deploy script From c3117750428279663d42d57bcf8154c1723d867c Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 30 Jul 2025 09:46:30 +0100 Subject: [PATCH 37/42] Revert "force runs of playground tests" This reverts commit 45231143495c2365f777de9a5c6e9f854a0acb74. --- .github/workflows/test-and-check.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-and-check.yml b/.github/workflows/test-and-check.yml index 027e3f381f14..b6023b3e1fd0 100644 --- a/.github/workflows/test-and-check.yml +++ b/.github/workflows/test-and-check.yml @@ -93,24 +93,24 @@ jobs: - os: macos-latest description: macOS node_version: 20.19.1 - filter: '--filter="./packages/vite-plugin-cloudflare/playground" --force' + filter: '--filter="./packages/*" --filter="./fixtures/*" --filter="./packages/vite-plugin-cloudflare/playground" --summarize' # needs to run on the amd runners to allow containers test to work in CI - os: ubuntu-24.04 description: Linux node_version: 20.19.1 # ./tools _only_ runs here because they're only intended to run in CI # Browser rendering is disabled here because of https://pptr.dev/troubleshooting#issues-with-apparmor-on-ubuntu - filter: '--filter="./packages/vite-plugin-cloudflare/playground" --force' + filter: '--filter="./tools" --filter="./packages/*" --filter="./fixtures/*" --filter="./packages/vite-plugin-cloudflare/playground" --filter="!./fixtures/browser-rendering"' - os: windows-latest description: Windows node_version: 20.19.1 - filter: '--filter="./packages/vite-plugin-cloudflare/playground" --force' + filter: '--filter="./packages/*" --filter="./fixtures/*" --filter="./packages/vite-plugin-cloudflare/playground"' # needs to run on the amd runners to allow containers test to work in CI - os: ubuntu-24.04 description: v22, Linux node_version: 22 # Browser rendering is disabled here because of https://pptr.dev/troubleshooting#issues-with-apparmor-on-ubuntu - filter: '--filter="./packages/vite-plugin-cloudflare/playground" --force' + filter: '--filter="./packages/*" --filter="./fixtures/*" --filter="./packages/vite-plugin-cloudflare/playground" --filter="!./packages/kv-asset-handler" --filter="!./fixtures/browser-rendering"' # Skipped until we upgrade to undici v7, because of https://github.com/nodejs/undici/issues/4285 # - os: ubuntu-24.04-arm # label: v24, Linux From 2a555d40a066c05b6c354072ff8b199e47354946 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 30 Jul 2025 10:53:47 +0100 Subject: [PATCH 38/42] longer timeout on the container fixture test --- fixtures/interactive-dev-tests/tests/index.test.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fixtures/interactive-dev-tests/tests/index.test.ts b/fixtures/interactive-dev-tests/tests/index.test.ts index 5bf71077114b..a0da4658447d 100644 --- a/fixtures/interactive-dev-tests/tests/index.test.ts +++ b/fixtures/interactive-dev-tests/tests/index.test.ts @@ -719,10 +719,13 @@ baseDescribe.skipIf(process.platform !== "linux" && process.env.CI === "true")( await new Promise((resolve) => { wrangler.pty.onExit(() => resolve()); }); - await vi.waitFor(() => { - const remainingIds = getContainerIds(); - expect(remainingIds.length).toBe(0); - }); + await vi.waitFor( + () => { + const remainingIds = getContainerIds(); + expect(remainingIds.length).toBe(0); + }, + { timeout: 10_000, interval: 1000 } + ); }); } ); From 0f93e5e570fb5518cd45b8484f08c23ae53b5222 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 30 Jul 2025 11:06:16 +0100 Subject: [PATCH 39/42] correctly unwatch config files --- packages/vite-plugin-cloudflare/src/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index 72de2abcc252..52cc20ed7779 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -373,7 +373,7 @@ if (import.meta.hot) { miniflare ); - viteDevServer.watcher.once("change", async (changedFilePath) => { + const configChangedHandler = async (changedFilePath: string) => { assertIsNotPreview(resolvedPluginConfig); if ( @@ -386,6 +386,7 @@ if (import.meta.hot) { ) ) { debuglog(configId, "Config changed: " + changedFilePath); + viteDevServer.watcher.off("change", configChangedHandler); if (!restartAbortController.signal.aborted) { debuglog( configId, @@ -401,7 +402,8 @@ if (import.meta.hot) { ); } } - }); + }; + viteDevServer.watcher.on("change", configChangedHandler); let containerBuildId: string | undefined; const entryWorkerConfig = getEntryWorkerConfig(resolvedPluginConfig); From faba736b5ef1e73719ff4715b4a8d3a439cf9558 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 30 Jul 2025 11:07:21 +0100 Subject: [PATCH 40/42] revert interactive dev fix --- fixtures/interactive-dev-tests/tests/index.test.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/fixtures/interactive-dev-tests/tests/index.test.ts b/fixtures/interactive-dev-tests/tests/index.test.ts index a0da4658447d..341ac2d87477 100644 --- a/fixtures/interactive-dev-tests/tests/index.test.ts +++ b/fixtures/interactive-dev-tests/tests/index.test.ts @@ -719,13 +719,10 @@ baseDescribe.skipIf(process.platform !== "linux" && process.env.CI === "true")( await new Promise((resolve) => { wrangler.pty.onExit(() => resolve()); }); - await vi.waitFor( - () => { - const remainingIds = getContainerIds(); - expect(remainingIds.length).toBe(0); - }, - { timeout: 10_000, interval: 1000 } - ); + vi.waitFor(() => { + const remainingIds = getContainerIds(); + expect(remainingIds.length).toBe(0); + }); }); } ); From 5a4592b27c470cf5be28f468925910b43d338e2a Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 30 Jul 2025 11:20:06 +0100 Subject: [PATCH 41/42] cleanup beforeAll in vitest-setup Avoid the `server` variable being global and mutated --- .../playground/vitest-setup.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/vite-plugin-cloudflare/playground/vitest-setup.ts b/packages/vite-plugin-cloudflare/playground/vitest-setup.ts index d024266a633a..1779b38b631d 100644 --- a/packages/vite-plugin-cloudflare/playground/vitest-setup.ts +++ b/packages/vite-plugin-cloudflare/playground/vitest-setup.ts @@ -32,8 +32,6 @@ export const isWindows = process.platform === "win32"; export const isCINonLinux = process.platform !== "linux" && process.env.CI === "true"; -let server: ViteDevServer | http.Server | PreviewServer; - /** * Vite Dev Server when testing serve */ @@ -85,6 +83,8 @@ export function resetServerLogs() { } beforeAll(async (s) => { + let server: ViteDevServer | http.Server | PreviewServer | undefined; + const suite = s as RunnerTestFile; testPath = suite.filepath!; @@ -180,9 +180,7 @@ beforeAll(async (s) => { await page?.close(); await server?.close(); await watcher?.close(); - if (browser) { - await browser.close(); - } + await browser?.close(); }; }, 15_000); @@ -256,12 +254,13 @@ export async function startDefaultServe(): Promise< if (!isBuild) { process.env.VITE_INLINE = "inline-serve"; const config = await loadConfig({ command: "serve", mode: "development" }); - viteServer = server = await (await createServer(config)).listen(); - viteTestUrl = server!.resolvedUrls!.local[0]!; - if (server.config.base === "/") { + viteServer = await (await createServer(config)).listen(); + viteTestUrl = viteServer.resolvedUrls!.local[0]!; + if (viteServer.config.base === "/") { viteTestUrl = viteTestUrl.replace(/\/$/, ""); } await page.goto(viteTestUrl); + return viteServer; } else { process.env.VITE_INLINE = "inline-build"; // determine build watch @@ -299,10 +298,9 @@ export async function startDefaultServe(): Promise< if (previewServer.config.base === "/") { viteTestUrl = viteTestUrl.replace(/\/$/, ""); } - server = previewServer; await page.goto(viteTestUrl); + return previewServer; } - return server; } /** From 7ec7a0c7d4ae8454873a193f98efc2de87833e4e Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 30 Jul 2025 11:22:44 +0100 Subject: [PATCH 42/42] remove redundant change to `restartingServer` flag --- packages/vite-plugin-cloudflare/src/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/vite-plugin-cloudflare/src/index.ts b/packages/vite-plugin-cloudflare/src/index.ts index 52cc20ed7779..f3fce71f2672 100644 --- a/packages/vite-plugin-cloudflare/src/index.ts +++ b/packages/vite-plugin-cloudflare/src/index.ts @@ -740,9 +740,6 @@ if (import.meta.hot) { }); miniflare = undefined; } - // Reset the flag so that if a `buildEnd` hook is called again before the next - // configureServer hook then we do dispose of miniflare correctly. - restartingServer = false; }, }, // Plugin to provide a fallback entry file