Skip to content

Commit 678cc2c

Browse files
emily-shenpenalosa
authored andcommitted
feat: graduate --x-include-runtime (#8166)
* graduate wrangler type generation to GA * fixups * extra changeset
1 parent cda18a2 commit 678cc2c

File tree

17 files changed

+1002
-624
lines changed

17 files changed

+1002
-624
lines changed

.changeset/nasty-kiwis-talk.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
Include runtime types in the output of `wrangler types` by default
6+
7+
`wrangler types` will now produce one file that contains both `Env` types and runtime types based on your compatibility date and flags. This is located at `worker-configuration.d.ts` by default.
8+
9+
This behaviour was previously gated behind `--experimental-include-runtime`. That flag is no longer necessary and has been removed. It has been replaced by `--include-runtime` and `--include-env`, both of which are set to `true` by default. If you were previously using `--x-include-runtime`, you can drop that flag and remove the separate `runtime.d.ts` file.
10+
11+
If you were previously using `@cloudflare/workers-types` we recommend you run uninstall (e.g. `npm uninstall @cloudflare/workers-types`) and run `wrangler types` instead. Note that `@cloudflare/workers-types` will continue to be published.

.changeset/shiny-donkeys-act.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
feat: prompt users to rerun `wrangler types` during `wrangler dev`
6+
7+
If a generated types file is found at the default output location of `wrangler types` (`worker-configuration.d.ts`), remind users to rerun `wrangler types` if it looks like they're out of date.

fixtures/type-generation/package.json

Lines changed: 0 additions & 16 deletions
This file was deleted.

fixtures/type-generation/tests/type-generation.file-comment.test.ts

Lines changed: 0 additions & 61 deletions
This file was deleted.

fixtures/type-generation/vitest.config.mts

Lines changed: 0 additions & 9 deletions
This file was deleted.

fixtures/type-generation/wrangler.toml

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 111 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { existsSync } from "node:fs";
2-
import { readFile, writeFile } from "node:fs/promises";
1+
import { readFileSync } from "node:fs";
2+
import { writeFile } from "node:fs/promises";
33
import path from "node:path";
44
import { describe, expect, it } from "vitest";
55
import { dedent } from "../src/utils/dedent";
@@ -11,6 +11,8 @@ const seed = {
1111
main = "src/index.ts"
1212
compatibility_date = "2023-01-01"
1313
compatibility_flags = ["nodejs_compat", "no_global_navigator"]
14+
[vars]
15+
MY_VAR = "my-var-value"
1416
`,
1517
"src/index.ts": dedent`
1618
export default {
@@ -29,159 +31,156 @@ const seed = {
2931
};
3032

3133
describe("types", () => {
32-
it("should not generate runtime types without flag", async () => {
34+
it("should generate runtime types without a flag", async () => {
3335
const helper = new WranglerE2ETestHelper();
3436
await helper.seed(seed);
3537
const output = await helper.run(`wrangler types`);
3638

37-
expect(output.stdout).not.toContain(`Generating runtime types...`);
39+
expect(output.stdout).toContain("Generating runtime types...");
40+
expect(output.stdout).toContain("Runtime types generated.");
41+
expect(output.stdout).toContain(
42+
"✨ Types written to worker-configuration.d.ts"
43+
);
44+
expect(output.stdout).toContain("📖 Read about runtime types");
3845
});
3946

40-
it("should generate runtime types at the default path", async () => {
47+
it("should generate runtime types and env types in one file at the default path", async () => {
4148
const helper = new WranglerE2ETestHelper();
4249
await helper.seed(seed);
43-
const output = await helper.run(`wrangler types --x-include-runtime`);
44-
45-
const fileExists = existsSync(
46-
path.join(helper.tmpPath, "./.wrangler/types/runtime.d.ts")
47-
);
48-
49-
expect(fileExists).toEqual(true);
50-
expect(output.stdout).toContain(`Generating runtime types...`);
51-
expect(output.stdout).toContain(`Generating project types...`);
52-
expect(output.stdout).toContain(
53-
`✨ Runtime types written to ./.wrangler/types/runtime.d.ts`
54-
);
55-
expect(output.stdout).toContain(
56-
`"types": ["./.wrangler/types/runtime.d.ts"]`
57-
);
50+
const output = await helper.run(`wrangler types`);
51+
expect(output.stdout).toContain("Generating project types...");
52+
expect(output.stdout).toContain("interface Env {");
53+
expect(output.stdout).toContain("Generating runtime types...");
54+
expect(output.stdout).toContain("Runtime types generated.");
5855
expect(output.stdout).toContain(
59-
`📣 Since you have Node.js compatibility mode enabled, you should consider adding Node.js for TypeScript by running "npm i --save-dev @types/[email protected]". Please see the docs for more details: https://developers.cloudflare.com/workers/languages/typescript/#transitive-loading-of-typesnode-overrides-cloudflareworkers-types`
56+
"✨ Types written to worker-configuration.d.ts"
6057
);
61-
expect(output.stdout).toContain(
62-
`Remember to run 'wrangler types --x-include-runtime' again if you change 'compatibility_date' or 'compatibility_flags' in your wrangler.toml file.`
58+
const file = readFileSync(
59+
path.join(helper.tmpPath, "./worker-configuration.d.ts"),
60+
"utf8"
6361
);
62+
expect(file).contains('declare module "cloudflare:workers"');
63+
expect(file).contains("interface Env");
6464
});
6565

66-
it("should generate runtime types at the provided path", async () => {
66+
it("should be able to generate an Env type only", async () => {
6767
const helper = new WranglerE2ETestHelper();
6868
await helper.seed(seed);
69-
const output = await helper.run(
70-
`wrangler types --x-include-runtime="./types.d.ts"`
69+
const output = await helper.run(`wrangler types --include-runtime=false`);
70+
expect(output.stdout).not.toContain("Generating runtime types...");
71+
const file = readFileSync(
72+
path.join(helper.tmpPath, "./worker-configuration.d.ts"),
73+
"utf8"
7174
);
72-
73-
const fileExists = existsSync(path.join(helper.tmpPath, "./types.d.ts"));
74-
75-
expect(fileExists).toEqual(true);
76-
expect(output.stdout).toContain(`✨ Runtime types written to ./types.d.ts`);
77-
expect(output.stdout).toContain(`"types": ["./types.d.ts"]`);
75+
expect(file).toMatchInlineSnapshot(`
76+
"// Generated by Wrangler by running \`wrangler types --include-runtime=false\` (hash: 7fbca0b39560512499078acfe5f450c0)
77+
interface Env {
78+
MY_VAR: "my-var-value";
79+
}
80+
"
81+
`);
7882
});
7983

80-
it("should generate types", async () => {
84+
it("should include header with version information in the generated types", async () => {
8185
const helper = new WranglerE2ETestHelper();
8286
await helper.seed(seed);
83-
await helper.run(`wrangler types --x-include-runtime="./types.d.ts"`);
87+
await helper.run(`wrangler types "./types.d.ts" `);
8488

85-
const file = (
86-
await readFile(path.join(helper.tmpPath, "./types.d.ts"))
87-
).toString();
89+
const lines = readFileSync(
90+
path.join(helper.tmpPath, "./types.d.ts"),
91+
"utf8"
92+
).split("\n");
8893

89-
expect(file).contains('declare module "cloudflare:workers"');
94+
expect(lines[0]).toMatchInlineSnapshot(
95+
`"// Generated by Wrangler by running \`wrangler types ./types.d.ts\` (hash: 7fbca0b39560512499078acfe5f450c0)"`
96+
);
97+
expect(lines[1]).match(
98+
/\/\/ Runtime types generated with workerd@1\.\d{8}\.\d \d{4}-\d{2}-\d{2} ([a-z_]+,?)*/
99+
);
90100
});
91101

92-
it("should recommend to uninstall @cloudflare/workers-types", async () => {
102+
it("should include header with wrangler command that generated it", async () => {
93103
const helper = new WranglerE2ETestHelper();
94104
await helper.seed({
95105
...seed,
96-
"tsconfig.json": dedent`
97-
{
98-
"compilerOptions": {
99-
"types": ["@cloudflare/workers-types"]
100-
}
101-
}
102-
`,
106+
"wranglerA.toml": dedent`
107+
name = "test-worker"
108+
main = "src/index.ts"
109+
compatibility_date = "2023-01-01"
110+
`,
103111
});
104-
const output = await helper.run(
105-
`wrangler types --x-include-runtime="./types.d.ts"`
112+
await helper.run(
113+
"wrangler types -c wranglerA.toml --env-interface MyCloudflareEnv ./cflare-env.d.ts"
106114
);
107115

108-
expect(output.stdout).toContain(
109-
`📣 You can now uninstall "@cloudflare/workers-types".`
116+
const lines = readFileSync(
117+
path.join(helper.tmpPath, "./cflare-env.d.ts"),
118+
"utf8"
119+
).split("\n");
120+
121+
expect(lines[0]).toMatchInlineSnapshot(
122+
`"// Generated by Wrangler by running \`wrangler types -c wranglerA.toml --env-interface MyCloudflareEnv ./cflare-env.d.ts\` (hash: 8fcf1ed67a52a2d34d6d34c3068e89b8)"`
123+
);
124+
expect(lines[1]).match(
125+
/\/\/ Runtime types generated with workerd@1\.\d{8}\.\d \d{4}-\d{2}-\d{2} ([a-z_]+,?)*/
110126
);
111127
});
112128

113-
it("should not recommend to install @types/node if 'node' exists in types array", async () => {
129+
it("should not regenerate runtime types if the header matches, but should regenerate env types", async () => {
114130
const helper = new WranglerE2ETestHelper();
115-
await helper.seed({
116-
...seed,
117-
"tsconfig.json": dedent`
118-
{
119-
"compilerOptions": {
120-
"types": ["node"]
121-
}
122-
}
123-
`,
124-
});
125-
const output = await helper.run(
126-
`wrangler types --x-include-runtime="./types.d.ts"`
131+
await helper.seed(seed);
132+
await helper.run(`wrangler types`);
133+
134+
const typesPath = path.join(helper.tmpPath, "worker-configuration.d.ts");
135+
const file = readFileSync(typesPath, "utf8").split("\n");
136+
137+
await writeFile(
138+
typesPath,
139+
[
140+
file[0],
141+
file[1],
142+
"FAKE ENV",
143+
"// Begin runtime types",
144+
"FAKE RUNTIME",
145+
].join("\n")
127146
);
128147

129-
expect(output.stdout).not.toContain(
130-
`📣 Since you have Node.js compatibility mode enabled, you should consider adding Node.js for TypeScript by running "npm i --save-dev @types/[email protected]". Please see the docs for more details: https://developers.cloudflare.com/workers/languages/typescript/#transitive-loading-of-typesnode-overrides-cloudflareworkers-types`
131-
);
148+
await helper.run(`wrangler types`);
149+
150+
const file2 = readFileSync(typesPath, "utf8");
151+
152+
// regenerates env types
153+
expect(file2).toContain("interface Env {");
154+
// uses cached runtime types
155+
expect(file2).toContain("// Begin runtime types");
156+
expect(file2).toContain("FAKE RUNTIME");
132157
});
133158

134-
it("should not error with nodejs_compat flags", async () => {
159+
it("should prompt you to update types if they've been changed", async () => {
135160
const helper = new WranglerE2ETestHelper();
136-
await helper.seed({
137-
...seed,
138-
"wrangler.toml": dedent`
161+
await helper.seed(seed);
162+
await helper.run(`wrangler types`);
163+
seed["wrangler.toml"] = dedent`
139164
name = "test-worker"
140165
main = "src/index.ts"
141166
compatibility_date = "2023-01-01"
142-
compatibility_flags = ["nodejs_compat", "experimental:nodejs_compat_v2"]
143-
`,
144-
});
145-
146-
const output = await helper.run(
147-
`wrangler types --x-include-runtime="./types.d.ts"`
148-
);
149-
150-
expect(output.stderr).toBe("");
151-
expect(output.status).toBe(0);
152-
});
153-
it("should include header with version information in the generated types", async () => {
154-
const helper = new WranglerE2ETestHelper();
167+
compatibility_flags = ["nodejs_compat", "no_global_navigator"]
168+
[vars]
169+
BEEP = "BOOP"
170+
`;
155171
await helper.seed(seed);
156-
await helper.run(`wrangler types --x-include-runtime="./types.d.ts"`);
157-
158-
const file = (
159-
await readFile(path.join(helper.tmpPath, "./types.d.ts"))
160-
).toString();
161-
162-
expect(file.split("\n")[0]).match(
163-
/\/\/ Runtime types generated with workerd@1\.\d+\.\d \d\d\d\d-\d\d-\d\d ([a-z_]+,?)*/
164-
);
165-
});
166-
it("should not regenerate types if the header matches", async () => {
167-
const helper = new WranglerE2ETestHelper();
172+
const worker = helper.runLongLived("wrangler dev");
173+
await worker.readUntil(/ Your types might be out of date./);
174+
seed["wrangler.toml"] = dedent`
175+
name = "test-worker"
176+
main = "src/index.ts"
177+
compatibility_date = "2023-01-01"
178+
compatibility_flags = ["nodejs_compat"]
179+
[vars]
180+
BEEP = "BOOP"
181+
ASDf = "ADSfadsf"
182+
`;
168183
await helper.seed(seed);
169-
await helper.run(`wrangler types --x-include-runtime`);
170-
171-
const runtimeTypesFile = path.join(
172-
helper.tmpPath,
173-
"./.wrangler/types/runtime.d.ts"
174-
);
175-
const file = (await readFile(runtimeTypesFile)).toString();
176-
177-
const header = file.split("\n")[0];
178-
179-
await writeFile(runtimeTypesFile, header + "\n" + "SOME_RANDOM_DATA");
180-
181-
await helper.run(`wrangler types --x-include-runtime`);
182-
183-
const file2 = (await readFile(runtimeTypesFile)).toString();
184-
185-
expect(file2.split("\n")[1]).toBe("SOME_RANDOM_DATA");
184+
await worker.readUntil(/ Your types might be out of date./);
186185
});
187186
});

0 commit comments

Comments
 (0)