From c135de4707234e11f7f6438bea6a7067e8f284f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Somhairle=20MacLe=C3=B2id?= Date: Mon, 16 Sep 2024 14:58:14 +0100 Subject: [PATCH] Add header + caching to runtime type generation (#6329) * Add header + caching to runtime type generation * Create perfect-pens-work.md * Update packages/wrangler/src/type-generation/runtime/index.ts Co-authored-by: Andy Jessop --------- Co-authored-by: Andy Jessop --- .changeset/perfect-pens-work.md | 5 +++ packages/wrangler/e2e/types.test.ts | 38 ++++++++++++++++++- .../wrangler/src/type-generation/index.ts | 3 +- .../src/type-generation/runtime/index.ts | 20 +++++++++- packages/wrangler/src/workerd.d.ts | 6 +++ 5 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 .changeset/perfect-pens-work.md create mode 100644 packages/wrangler/src/workerd.d.ts diff --git a/.changeset/perfect-pens-work.md b/.changeset/perfect-pens-work.md new file mode 100644 index 000000000000..af7ea2956ac4 --- /dev/null +++ b/.changeset/perfect-pens-work.md @@ -0,0 +1,5 @@ +--- +"wrangler": patch +--- + +chore: Cache generated runtime types diff --git a/packages/wrangler/e2e/types.test.ts b/packages/wrangler/e2e/types.test.ts index f2a76956b0ca..9c7c0d8ce3dd 100644 --- a/packages/wrangler/e2e/types.test.ts +++ b/packages/wrangler/e2e/types.test.ts @@ -1,5 +1,5 @@ import { existsSync } from "node:fs"; -import { readFile } from "node:fs/promises"; +import { readFile, writeFile } from "node:fs/promises"; import path from "node:path"; import { describe, expect, it } from "vitest"; import { dedent } from "../src/utils/dedent"; @@ -10,7 +10,7 @@ const seed = { name = "test-worker" main = "src/index.ts" compatibility_date = "2023-01-01" - compatibility_flags = ["nodejs_compat"] + compatibility_flags = ["nodejs_compat", "no_global_navigator"] `, "src/index.ts": dedent` export default { @@ -150,4 +150,38 @@ describe("types", () => { 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(); + 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(); + 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"); + }); }); diff --git a/packages/wrangler/src/type-generation/index.ts b/packages/wrangler/src/type-generation/index.ts index d4d04295b340..4eef39ce2875 100644 --- a/packages/wrangler/src/type-generation/index.ts +++ b/packages/wrangler/src/type-generation/index.ts @@ -489,8 +489,7 @@ function writeDTSFile({ fs.writeFileSync( path, [ - `// Generated by Wrangler on ${new Date()}`, - `// by running \`${wranglerCommandUsed}\``, + `// Generated by Wrangler by running \`${wranglerCommandUsed}\``, "", combinedTypeStrings, ].join("\n") diff --git a/packages/wrangler/src/type-generation/runtime/index.ts b/packages/wrangler/src/type-generation/runtime/index.ts index 1d2c275ffad8..58c6bdc88608 100644 --- a/packages/wrangler/src/type-generation/runtime/index.ts +++ b/packages/wrangler/src/type-generation/runtime/index.ts @@ -1,6 +1,8 @@ import { readFileSync } from "fs"; -import { writeFile } from "fs/promises"; +import { readFile, writeFile } from "fs/promises"; import { Miniflare } from "miniflare"; +import { version } from "workerd"; +import { logger } from "../../logger"; import { ensureDirectoryExists } from "../../utils/filesystem"; import type { Config } from "../../config/config"; @@ -47,6 +49,20 @@ export async function generateRuntimeTypes({ await ensureDirectoryExists(outFile); + const header = `// Runtime types generated with workerd@${version} ${compatibility_date} ${compatibility_flags.join(",")}`; + + try { + const existingTypes = await readFile(outFile, "utf8"); + if (existingTypes.split("\n")[0] === header) { + logger.debug("Using cached runtime types: ", header); + return { outFile }; + } + } catch (e) { + if ((e as { code: string }).code !== "ENOENT") { + throw e; + } + } + const types = await generate({ compatibilityDate: compatibility_date, // Ignore nodejs compat flags as there is currently no mechanism to generate these dynamically. @@ -55,7 +71,7 @@ export async function generateRuntimeTypes({ ), }); - await writeFile(outFile, types, "utf8"); + await writeFile(outFile, `${header}\n${types}`, "utf8"); return { outFile, diff --git a/packages/wrangler/src/workerd.d.ts b/packages/wrangler/src/workerd.d.ts new file mode 100644 index 000000000000..1b6e6e04e334 --- /dev/null +++ b/packages/wrangler/src/workerd.d.ts @@ -0,0 +1,6 @@ +declare module "workerd" { + const path: string; + export default path; + export const compatibilityDate: string; + export const version: string; +}