-
Notifications
You must be signed in to change notification settings - Fork 1k
feat: graduate --x-include-runtime
#8166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| --- | ||
| "wrangler": minor | ||
| --- | ||
|
|
||
| Include runtime types in the output of `wrangler types` by default | ||
|
|
||
| `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. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth taking this opportunity to rename this file, maybe to |
||
|
|
||
| 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. | ||
|
|
||
| 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. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| "wrangler": minor | ||
| --- | ||
|
|
||
| feat: prompt users to rerun `wrangler types` during `wrangler dev` | ||
|
|
||
| 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. |
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| import { existsSync } from "node:fs"; | ||
| import { readFile, writeFile } from "node:fs/promises"; | ||
| import { readFileSync } from "node:fs"; | ||
| import { writeFile } from "node:fs/promises"; | ||
| import path from "node:path"; | ||
| import { describe, expect, it } from "vitest"; | ||
| import { dedent } from "../src/utils/dedent"; | ||
|
|
@@ -11,6 +11,8 @@ const seed = { | |
| main = "src/index.ts" | ||
| compatibility_date = "2023-01-01" | ||
| compatibility_flags = ["nodejs_compat", "no_global_navigator"] | ||
| [vars] | ||
| MY_VAR = "my-var-value" | ||
| `, | ||
| "src/index.ts": dedent` | ||
| export default { | ||
|
|
@@ -29,159 +31,156 @@ const seed = { | |
| }; | ||
|
|
||
| describe("types", () => { | ||
| it("should not generate runtime types without flag", async () => { | ||
| it("should generate runtime types without a flag", async () => { | ||
| const helper = new WranglerE2ETestHelper(); | ||
| await helper.seed(seed); | ||
| const output = await helper.run(`wrangler types`); | ||
|
|
||
| expect(output.stdout).not.toContain(`Generating runtime types...`); | ||
| expect(output.stdout).toContain("Generating runtime types..."); | ||
| expect(output.stdout).toContain("Runtime types generated."); | ||
| expect(output.stdout).toContain( | ||
| "✨ Types written to worker-configuration.d.ts" | ||
| ); | ||
| expect(output.stdout).toContain("📖 Read about runtime types"); | ||
| }); | ||
|
|
||
| it("should generate runtime types at the default path", async () => { | ||
| it("should generate runtime types and env types in one file at the default path", async () => { | ||
| const helper = new WranglerE2ETestHelper(); | ||
| await helper.seed(seed); | ||
| const output = await helper.run(`wrangler types --x-include-runtime`); | ||
|
|
||
| const fileExists = existsSync( | ||
| path.join(helper.tmpPath, "./.wrangler/types/runtime.d.ts") | ||
| ); | ||
|
|
||
| expect(fileExists).toEqual(true); | ||
| expect(output.stdout).toContain(`Generating runtime types...`); | ||
| expect(output.stdout).toContain(`Generating project types...`); | ||
| expect(output.stdout).toContain( | ||
| `✨ Runtime types written to ./.wrangler/types/runtime.d.ts` | ||
| ); | ||
| expect(output.stdout).toContain( | ||
| `"types": ["./.wrangler/types/runtime.d.ts"]` | ||
| ); | ||
| const output = await helper.run(`wrangler types`); | ||
| expect(output.stdout).toContain("Generating project types..."); | ||
| expect(output.stdout).toContain("interface Env {"); | ||
| expect(output.stdout).toContain("Generating runtime types..."); | ||
| expect(output.stdout).toContain("Runtime types generated."); | ||
| expect(output.stdout).toContain( | ||
| `📣 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` | ||
emily-shen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "✨ Types written to worker-configuration.d.ts" | ||
| ); | ||
| expect(output.stdout).toContain( | ||
| `Remember to run 'wrangler types --x-include-runtime' again if you change 'compatibility_date' or 'compatibility_flags' in your wrangler.toml file.` | ||
| const file = readFileSync( | ||
| path.join(helper.tmpPath, "./worker-configuration.d.ts"), | ||
| "utf8" | ||
| ); | ||
| expect(file).contains('declare module "cloudflare:workers"'); | ||
| expect(file).contains("interface Env"); | ||
| }); | ||
|
|
||
| it("should generate runtime types at the provided path", async () => { | ||
| it("should be able to generate an Env type only", async () => { | ||
| const helper = new WranglerE2ETestHelper(); | ||
| await helper.seed(seed); | ||
| const output = await helper.run( | ||
| `wrangler types --x-include-runtime="./types.d.ts"` | ||
| const output = await helper.run(`wrangler types --include-runtime=false`); | ||
emily-shen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| expect(output.stdout).not.toContain("Generating runtime types..."); | ||
| const file = readFileSync( | ||
| path.join(helper.tmpPath, "./worker-configuration.d.ts"), | ||
| "utf8" | ||
| ); | ||
|
|
||
| const fileExists = existsSync(path.join(helper.tmpPath, "./types.d.ts")); | ||
|
|
||
| expect(fileExists).toEqual(true); | ||
| expect(output.stdout).toContain(`✨ Runtime types written to ./types.d.ts`); | ||
| expect(output.stdout).toContain(`"types": ["./types.d.ts"]`); | ||
| expect(file).toMatchInlineSnapshot(` | ||
| "// Generated by Wrangler by running \`wrangler types --include-runtime=false\` (hash: 7fbca0b39560512499078acfe5f450c0) | ||
| interface Env { | ||
| MY_VAR: "my-var-value"; | ||
| } | ||
| " | ||
| `); | ||
| }); | ||
|
|
||
| it("should generate types", async () => { | ||
| it("should include header with version information in the generated types", async () => { | ||
| const helper = new WranglerE2ETestHelper(); | ||
| await helper.seed(seed); | ||
| await helper.run(`wrangler types --x-include-runtime="./types.d.ts"`); | ||
| await helper.run(`wrangler types "./types.d.ts" `); | ||
|
|
||
| const file = ( | ||
| await readFile(path.join(helper.tmpPath, "./types.d.ts")) | ||
| ).toString(); | ||
| const lines = readFileSync( | ||
| path.join(helper.tmpPath, "./types.d.ts"), | ||
| "utf8" | ||
| ).split("\n"); | ||
|
|
||
| expect(file).contains('declare module "cloudflare:workers"'); | ||
| expect(lines[0]).toMatchInlineSnapshot( | ||
| `"// Generated by Wrangler by running \`wrangler types ./types.d.ts\` (hash: 7fbca0b39560512499078acfe5f450c0)"` | ||
| ); | ||
| expect(lines[1]).match( | ||
| /\/\/ Runtime types generated with workerd@1\.\d{8}\.\d \d{4}-\d{2}-\d{2} ([a-z_]+,?)*/ | ||
| ); | ||
| }); | ||
|
|
||
| it("should recommend to uninstall @cloudflare/workers-types", async () => { | ||
| it("should include header with wrangler command that generated it", async () => { | ||
| const helper = new WranglerE2ETestHelper(); | ||
| await helper.seed({ | ||
| ...seed, | ||
| "tsconfig.json": dedent` | ||
| { | ||
| "compilerOptions": { | ||
| "types": ["@cloudflare/workers-types"] | ||
| } | ||
| } | ||
| `, | ||
| "wranglerA.toml": dedent` | ||
| name = "test-worker" | ||
| main = "src/index.ts" | ||
| compatibility_date = "2023-01-01" | ||
| `, | ||
| }); | ||
| const output = await helper.run( | ||
| `wrangler types --x-include-runtime="./types.d.ts"` | ||
| await helper.run( | ||
| "wrangler types -c wranglerA.toml --env-interface MyCloudflareEnv ./cflare-env.d.ts" | ||
| ); | ||
|
|
||
| expect(output.stdout).toContain( | ||
| `📣 You can now uninstall "@cloudflare/workers-types".` | ||
| const lines = readFileSync( | ||
| path.join(helper.tmpPath, "./cflare-env.d.ts"), | ||
| "utf8" | ||
| ).split("\n"); | ||
|
|
||
| expect(lines[0]).toMatchInlineSnapshot( | ||
| `"// Generated by Wrangler by running \`wrangler types -c wranglerA.toml --env-interface MyCloudflareEnv ./cflare-env.d.ts\` (hash: 8fcf1ed67a52a2d34d6d34c3068e89b8)"` | ||
| ); | ||
| expect(lines[1]).match( | ||
| /\/\/ Runtime types generated with workerd@1\.\d{8}\.\d \d{4}-\d{2}-\d{2} ([a-z_]+,?)*/ | ||
| ); | ||
| }); | ||
|
|
||
| it("should not recommend to install @types/node if 'node' exists in types array", async () => { | ||
| it("should not regenerate runtime types if the header matches, but should regenerate env types", async () => { | ||
| const helper = new WranglerE2ETestHelper(); | ||
| await helper.seed({ | ||
| ...seed, | ||
| "tsconfig.json": dedent` | ||
| { | ||
| "compilerOptions": { | ||
| "types": ["node"] | ||
| } | ||
| } | ||
| `, | ||
| }); | ||
| const output = await helper.run( | ||
| `wrangler types --x-include-runtime="./types.d.ts"` | ||
| await helper.seed(seed); | ||
| await helper.run(`wrangler types`); | ||
|
|
||
| const typesPath = path.join(helper.tmpPath, "worker-configuration.d.ts"); | ||
| const file = readFileSync(typesPath, "utf8").split("\n"); | ||
|
|
||
| await writeFile( | ||
| typesPath, | ||
| [ | ||
| file[0], | ||
| file[1], | ||
| "FAKE ENV", | ||
| "// Begin runtime types", | ||
| "FAKE RUNTIME", | ||
| ].join("\n") | ||
| ); | ||
|
|
||
| expect(output.stdout).not.toContain( | ||
| `📣 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` | ||
| ); | ||
| await helper.run(`wrangler types`); | ||
|
|
||
| const file2 = readFileSync(typesPath, "utf8"); | ||
|
|
||
| // regenerates env types | ||
| expect(file2).toContain("interface Env {"); | ||
| // uses cached runtime types | ||
| expect(file2).toContain("// Begin runtime types"); | ||
| expect(file2).toContain("FAKE RUNTIME"); | ||
| }); | ||
|
|
||
| it("should not error with nodejs_compat flags", async () => { | ||
| it("should prompt you to update types if they've been changed", async () => { | ||
| const helper = new WranglerE2ETestHelper(); | ||
| await helper.seed({ | ||
| ...seed, | ||
| "wrangler.toml": dedent` | ||
| await helper.seed(seed); | ||
| await helper.run(`wrangler types`); | ||
| seed["wrangler.toml"] = dedent` | ||
| name = "test-worker" | ||
| main = "src/index.ts" | ||
| compatibility_date = "2023-01-01" | ||
| compatibility_flags = ["nodejs_compat", "experimental:nodejs_compat_v2"] | ||
| `, | ||
| }); | ||
|
|
||
| const output = await helper.run( | ||
| `wrangler types --x-include-runtime="./types.d.ts"` | ||
| ); | ||
|
|
||
| expect(output.stderr).toBe(""); | ||
| expect(output.status).toBe(0); | ||
| }); | ||
| it("should include header with version information in the generated types", async () => { | ||
| const helper = new WranglerE2ETestHelper(); | ||
| compatibility_flags = ["nodejs_compat", "no_global_navigator"] | ||
| [vars] | ||
| BEEP = "BOOP" | ||
| `; | ||
| await helper.seed(seed); | ||
| await helper.run(`wrangler types --x-include-runtime="./types.d.ts"`); | ||
|
|
||
| const file = ( | ||
| await readFile(path.join(helper.tmpPath, "./types.d.ts")) | ||
| ).toString(); | ||
|
|
||
| expect(file.split("\n")[0]).match( | ||
| /\/\/ Runtime types generated with workerd@1\.\d+\.\d \d\d\d\d-\d\d-\d\d ([a-z_]+,?)*/ | ||
| ); | ||
| }); | ||
| it("should not regenerate types if the header matches", async () => { | ||
| const helper = new WranglerE2ETestHelper(); | ||
| const worker = helper.runLongLived("wrangler dev"); | ||
| await worker.readUntil(/❓ Your types might be out of date./); | ||
| seed["wrangler.toml"] = dedent` | ||
| name = "test-worker" | ||
| main = "src/index.ts" | ||
| compatibility_date = "2023-01-01" | ||
| compatibility_flags = ["nodejs_compat"] | ||
| [vars] | ||
| BEEP = "BOOP" | ||
| ASDf = "ADSfadsf" | ||
| `; | ||
| await helper.seed(seed); | ||
| await helper.run(`wrangler types --x-include-runtime`); | ||
|
|
||
| const runtimeTypesFile = path.join( | ||
| helper.tmpPath, | ||
| "./.wrangler/types/runtime.d.ts" | ||
| ); | ||
| const file = (await readFile(runtimeTypesFile)).toString(); | ||
|
|
||
| const header = file.split("\n")[0]; | ||
|
|
||
| await writeFile(runtimeTypesFile, header + "\n" + "SOME_RANDOM_DATA"); | ||
|
|
||
| await helper.run(`wrangler types --x-include-runtime`); | ||
|
|
||
| const file2 = (await readFile(runtimeTypesFile)).toString(); | ||
|
|
||
| expect(file2.split("\n")[1]).toBe("SOME_RANDOM_DATA"); | ||
| await worker.readUntil(/❓ Your types might be out of date./); | ||
| }); | ||
| }); | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
major? pretty sure there's nothing breaking. inclusion in v4 is mostly for politeness as there's a fair amount of CI usage