Skip to content

Commit

Permalink
Locally overriding vars in wrangler dev (#879)
Browse files Browse the repository at this point in the history
* test: use `fs` consistently in dev tests

* feat: read `vars` overrides from a local file for `wrangler dev`

The `vars` bindings can be specified in the `wrangler.toml` configuration file.
But "secret" `vars` are usually only provided at the server -
either by creating them in the Dashboard UI, or using the `wrangler secret` command.

It is useful during development, to provide these types of variable locally.
When running `wrangler dev` we will look for a file called `.dev.vars`, situated
next to the `wrangler.toml` file (or in the current working directory if there is no
`wrangler.toml`). Any values in this file, formatted like a `dotenv` file, will add to
or override `vars` bindings provided in the `wrangler.toml`.

Related to #190
  • Loading branch information
petebacondarwin authored May 4, 2022
1 parent 1ad7570 commit f694313
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 7 deletions.
17 changes: 17 additions & 0 deletions .changeset/wild-donkeys-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"wrangler": patch
---

feat: read `vars` overrides from a local file for `wrangler dev`

The `vars` bindings can be specified in the `wrangler.toml` configuration file.
But "secret" `vars` are usually only provided at the server -
either by creating them in the Dashboard UI, or using the `wrangler secret` command.

It is useful during development, to provide these types of variable locally.
When running `wrangler dev` we will look for a file called `.dev.vars`, situated
next to the `wrangler.toml` file (or in the current working directory if there is no
`wrangler.toml`). Any values in this file, formatted like a `dotenv` file, will add to
or override `vars` bindings provided in the `wrangler.toml`.

Related to #190
19 changes: 18 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/wrangler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
"supports-color": "^9.2.2",
"timeago.js": "^4.0.2",
"tmp-promise": "^3.0.3",
"ts-dedent": "^2.2.0",
"undici": "^4.15.1",
"update-check": "^1.5.4",
"ws": "^8.5.0",
Expand Down
55 changes: 52 additions & 3 deletions packages/wrangler/src/__tests__/dev.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as fs from "node:fs";
import { readFileSync } from "node:fs";
import patchConsole from "patch-console";
import dedent from "ts-dedent";
import Dev from "../dev/dev";
import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
import { setMockResponse, unsetAllMocks } from "./helpers/mock-cfetch";
Expand Down Expand Up @@ -382,7 +382,7 @@ describe("wrangler dev", () => {

await runWrangler("dev index.js");

expect(readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(
expect(fs.readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(
`"export default { fetch(){ return new Response(123) } }"`
);

Expand Down Expand Up @@ -410,7 +410,7 @@ describe("wrangler dev", () => {

await runWrangler("dev index.js");

expect(readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(`
expect(fs.readFileSync("index.js", "utf-8")).toMatchInlineSnapshot(`
"export default { fetch(){ return new Response(123) } }
"
`);
Expand Down Expand Up @@ -615,6 +615,55 @@ describe("wrangler dev", () => {
expect(std.err).toMatchInlineSnapshot(`""`);
});
});

describe(".dev.vars", () => {
it("should override `vars` bindings from `wrangler.toml` with values in `.dev.vars`", async () => {
fs.writeFileSync("index.js", `export default {};`);

const localVarsEnvContent = dedent`
# Preceding comment
VAR_1="var #1 value" # End of line comment
VAR_3="var #3 value"
VAR_MULTI_LINE_1="A: line 1
line 2"
VAR_MULTI_LINE_2="B: line 1\\nline 2"
EMPTY=
UNQUOTED= unquoted value
`;
fs.writeFileSync(".dev.vars", localVarsEnvContent, "utf8");

writeWranglerToml({
main: "index.js",
vars: {
VAR_1: "original value 1",
VAR_2: "original value 2", // should not get overridden
VAR_3: "original value 3",
VAR_MULTI_LINE_1: "original multi-line 1",
VAR_MULTI_LINE_2: "original multi-line 2",
EMPTY: "original empty",
UNQUOTED: "original unquoted",
},
});
await runWrangler("dev");
const varBindings: Record<string, unknown> = (Dev as jest.Mock).mock
.calls[0][0].bindings.vars;

expect(varBindings).toEqual({
VAR_1: "var #1 value",
VAR_2: "original value 2",
VAR_3: "var #3 value",
VAR_MULTI_LINE_1: "A: line 1\nline 2",
VAR_MULTI_LINE_2: "B: line 1\nline 2",
EMPTY: "",
UNQUOTED: "unquoted value", // Note that whitespace is trimmed
});
expect(std.out).toMatchInlineSnapshot(
`"Add vars defined in \\".dev.vars\\" to the \\"vars\\" bindings."`
);
expect(std.warn).toMatchInlineSnapshot(`""`);
expect(std.err).toMatchInlineSnapshot(`""`);
});
});
});

function mockGetZones(domain: string, zones: { id: string }[] = []) {
Expand Down
38 changes: 38 additions & 0 deletions packages/wrangler/src/dev/dev-vars.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as fs from "node:fs";
import * as path from "node:path";
import dotenv from "dotenv";
import { logger } from "../logger";
import type { Config } from "../config";

/**
* Get the Worker `vars` bindings for a `wrangler dev` instance of a Worker.
*
* The `vars` bindings can be specified in the `wrangler.toml` configuration file.
* But "secret" `vars` are usually only provided at the server -
* either by creating them in the Dashboard UI, or using the `wrangler secret` command.
*
* It is useful during development, to provide these types of variable locally.
* When running `wrangler dev` we will look for a file called `.dev.vars`, situated
* next to the `wrangler.toml` file (or in the current working directory if there is no
* `wrangler.toml`).
*
* Any values in this file, formatted like a `dotenv` file, will add to or override `vars`
* bindings provided in the `wrangler.toml`.
*/
export function getVarsForDev(config: Config): Config["vars"] {
const configDir = path.resolve(path.dirname(config.configPath ?? "."));
const devVarsPath = path.resolve(configDir, ".dev.vars");
if (fs.existsSync(devVarsPath)) {
const devVarsRelativePath = path.relative(process.cwd(), devVarsPath);
logger.log(
`Add vars defined in "${devVarsRelativePath}" to the "vars" bindings.`
);
const devVars = dotenv.parse(fs.readFileSync(devVarsPath, "utf8"));
return {
...config.vars,
...devVars,
};
} else {
return config.vars;
}
}
7 changes: 4 additions & 3 deletions packages/wrangler/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { fetchResult } from "./cfetch";
import { findWranglerToml, readConfig } from "./config";
import { createWorkerUploadForm } from "./create-worker-upload-form";
import Dev from "./dev/dev";
import { getVarsForDev } from "./dev/dev-vars";
import { confirm, prompt } from "./dialogs";
import { getEntry } from "./entry";
import { DeprecationError } from "./errors";
Expand Down Expand Up @@ -746,7 +747,7 @@ export async function main(argv: string[]): Promise<void> {
type: "boolean",
})
.option("node-compat", {
describe: "Enable node.js compaitibility",
describe: "Enable node.js compatibility",
type: "boolean",
});
},
Expand Down Expand Up @@ -937,7 +938,7 @@ export async function main(argv: string[]): Promise<void> {
};
}
),
vars: config.vars,
vars: getVarsForDev(config),
wasm_modules: config.wasm_modules,
text_blobs: config.text_blobs,
data_blobs: config.data_blobs,
Expand Down Expand Up @@ -1044,7 +1045,7 @@ export async function main(argv: string[]): Promise<void> {
type: "boolean",
})
.option("node-compat", {
describe: "Enable node.js compaitibility",
describe: "Enable node.js compatibility",
type: "boolean",
})
.option("dry-run", {
Expand Down

0 comments on commit f694313

Please sign in to comment.