Skip to content

Commit a91dfe2

Browse files
committed
add option to use generated types
1 parent 2048ad5 commit a91dfe2

File tree

3 files changed

+101
-49
lines changed

3 files changed

+101
-49
lines changed

packages/create-cloudflare/src/cli.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
updatePackageScripts,
3535
} from "./templates";
3636
import { validateProjectDirectory } from "./validators";
37-
import { installWorkersTypes } from "./workers";
37+
import { generateWorkersTypes, installWorkersTypes } from "./workers";
3838
import { updateWranglerConfig } from "./wrangler/config";
3939
import type { C3Args, C3Context } from "types";
4040

@@ -154,7 +154,6 @@ const configure = async (ctx: C3Context) => {
154154
startSection("Configuring your application for Cloudflare", "Step 2 of 3");
155155

156156
await installWrangler();
157-
await installWorkersTypes(ctx);
158157

159158
// Note: This _must_ be called before the configure phase since
160159
// pre-existing workers assume its presence in their configure phase
@@ -168,6 +167,10 @@ const configure = async (ctx: C3Context) => {
168167
addWranglerToGitIgnore(ctx);
169168

170169
await updatePackageScripts(ctx);
170+
if (ctx.template.installWorkersTypes) {
171+
await installWorkersTypes(ctx);
172+
}
173+
await generateWorkersTypes(ctx);
171174

172175
await offerGit(ctx);
173176
await gitCommit(ctx);

packages/create-cloudflare/src/templates.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,16 @@ export type TemplateConfig = {
142142
/** The key of the package.json "scripts" entry for previewing the project. Defaults to undefined (there might not be such script) */
143143
previewScript?: string;
144144

145+
/** The file path to the generated types file. Defaults to worker-configuration.d.ts*/
146+
typesPath?: string;
147+
145148
/** The file path of the template. This is used internally and isn't a user facing config value.*/
146149
path?: string;
147150

148151
bindings?: Record<string, unknown>;
152+
153+
/** Don't generate types, use @cloudflare/workers-types instead. Usually because the framework is pinned to Wrangler 3. Default false. */
154+
installWorkersTypes?: boolean;
149155
};
150156

151157
type CopyFiles = (StaticFileMap | VariantInfo) & {
Lines changed: 90 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,103 @@
11
import { existsSync } from "fs";
2-
import { join } from "path";
2+
import { join, resolve } from "path";
33
import { warn } from "@cloudflare/cli";
44
import { brandColor, dim } from "@cloudflare/cli/colors";
5-
import { spinner } from "@cloudflare/cli/interactive";
5+
import { runCommand } from "helpers/command";
66
import { getLatestTypesEntrypoint } from "helpers/compatDate";
7-
import { readFile, usesTypescript, writeFile } from "helpers/files";
7+
import { readFile, readJSON, usesTypescript, writeFile } from "helpers/files";
88
import { detectPackageManager } from "helpers/packageManagers";
99
import { installPackages } from "helpers/packages";
1010
import * as jsonc from "jsonc-parser";
11-
import type { C3Context } from "types";
11+
import type { C3Context, PackageJson } from "types";
1212

1313
/**
14-
* Installs the latest version of the `@cloudflare/workers-types` package
15-
* and updates the .tsconfig file to use the latest entrypoint version.
14+
* Generate types using `wrangler types` and update tsconfig
1615
*/
17-
export async function installWorkersTypes(ctx: C3Context) {
18-
const { npm } = detectPackageManager();
1916

17+
export async function generateWorkersTypes(ctx: C3Context) {
2018
if (!usesTypescript(ctx)) {
2119
return;
2220
}
21+
const packageJsonPath = resolve("package.json");
22+
const packageManifest = readJSON(packageJsonPath) as PackageJson;
23+
if (!Object.keys(packageManifest.scripts ?? {}).includes("cf-typegen")) {
24+
return;
25+
}
2326

24-
await installPackages(["@cloudflare/workers-types"], {
25-
dev: true,
26-
startText: "Installing @cloudflare/workers-types",
27-
doneText: `${brandColor("installed")} ${dim(`via ${npm}`)}`,
27+
const { npm } = detectPackageManager();
28+
29+
const typesCmd = [npm, "run", "cf-typegen"];
30+
31+
await runCommand(typesCmd, {
32+
cwd: ctx.project.path,
33+
silent: true,
34+
env: {
35+
CLOUDFLARE_ACCOUNT_ID: ctx.account?.id,
36+
NODE_ENV: "production",
37+
},
38+
startText: "Generating types for your application",
39+
doneText: `${brandColor("generated")} ${dim(`to \`${ctx.template.typesPath ?? "worker-configuration.d.ts"}\` via \`${typesCmd.join(" ")}\``)}`,
2840
});
29-
await addWorkersTypesToTsConfig(ctx);
41+
42+
if (ctx.template.compatibilityFlags?.includes("nodejs_compat")) {
43+
await installPackages(["@types/node"], {
44+
dev: true,
45+
startText: "Installing @types/node",
46+
doneText: `${brandColor("installed")} ${dim(`via ${npm}`)}`,
47+
});
48+
}
49+
50+
delete packageManifest["devDependencies"]?.["@cloudflare/workers-types"];
51+
52+
writeFile(packageJsonPath, JSON.stringify(packageManifest, null, 2));
53+
await updateTsConfig(ctx);
3054
}
3155

32-
export async function addWorkersTypesToTsConfig(ctx: C3Context) {
56+
export async function updateTsConfig(ctx: C3Context) {
3357
const tsconfigPath = join(ctx.project.path, "tsconfig.json");
3458
if (!existsSync(tsconfigPath)) {
3559
return;
3660
}
3761

38-
const s = spinner();
39-
s.start("Adding latest types to `tsconfig.json`");
40-
4162
const tsconfig = readFile(tsconfigPath);
42-
const entrypointVersion = getLatestTypesEntrypoint(ctx);
43-
if (entrypointVersion === null) {
44-
s.stop(
45-
`${brandColor(
46-
"skipped",
47-
)} couldn't find latest compatible version of @cloudflare/workers-types`,
48-
);
49-
return;
50-
}
51-
52-
const typesEntrypoint = `@cloudflare/workers-types/${entrypointVersion}`;
5363

5464
try {
5565
const config = jsonc.parse(tsconfig);
5666
const currentTypes = config.compilerOptions?.types ?? [];
57-
58-
const explicitEntrypoint = (currentTypes as string[]).some((t) =>
59-
t.match(/@cloudflare\/workers-types\/\d{4}-\d{2}-\d{2}/),
60-
);
61-
62-
// If a type declaration with an explicit entrypoint exists, leave the types as is
63-
// Otherwise, add the latest entrypoint
64-
const newTypes = explicitEntrypoint
65-
? [...currentTypes]
66-
: [
67-
...currentTypes.filter(
68-
(t: string) => t !== "@cloudflare/workers-types",
69-
),
70-
typesEntrypoint,
71-
];
67+
let newTypes: string[];
68+
if (ctx.template.installWorkersTypes) {
69+
const entrypointVersion = getLatestTypesEntrypoint(ctx);
70+
if (entrypointVersion === null) {
71+
return;
72+
}
73+
const typesEntrypoint = `@cloudflare/workers-types/${entrypointVersion}`;
74+
const explicitEntrypoint = (currentTypes as string[]).some((t) =>
75+
t.match(/@cloudflare\/workers-types\/\d{4}-\d{2}-\d{2}/),
76+
);
77+
// If a type declaration with an explicit entrypoint exists, leave the types as is
78+
// Otherwise, add the latest entrypoint
79+
newTypes = explicitEntrypoint
80+
? [...currentTypes]
81+
: [
82+
...currentTypes.filter(
83+
(t: string) => t !== "@cloudflare/workers-types",
84+
),
85+
typesEntrypoint,
86+
];
87+
} else {
88+
newTypes = [
89+
...currentTypes.filter(
90+
(t: string) => !t.startsWith("@cloudflare/workers-types"),
91+
),
92+
ctx.template.typesPath ?? "./worker-configuration.d.ts",
93+
...(ctx.template.compatibilityFlags?.includes("nodejs_compat")
94+
? ["node"]
95+
: []),
96+
];
97+
}
98+
if (newTypes.sort() === currentTypes.sort()) {
99+
return;
100+
}
72101

73102
// If we detect any tabs, use tabs, otherwise use spaces.
74103
// We need to pass an explicit value here in order to preserve formatting properly.
@@ -86,10 +115,24 @@ export async function addWorkersTypesToTsConfig(ctx: C3Context) {
86115
const updated = jsonc.applyEdits(tsconfig, edits);
87116
writeFile(tsconfigPath, updated);
88117
} catch (error) {
89-
warn(
90-
"Failed to update `tsconfig.json` with latest `@cloudflare/workers-types` entrypoint.",
91-
);
118+
warn("Failed to update `tsconfig.json`.");
92119
}
120+
}
93121

94-
s.stop(`${brandColor("added")} ${dim(typesEntrypoint)}`);
122+
/**
123+
* Installs the latest version of the `@cloudflare/workers-types` package
124+
* and updates the .tsconfig file to use the latest entrypoint version.
125+
*/
126+
export async function installWorkersTypes(ctx: C3Context) {
127+
if (!usesTypescript(ctx)) {
128+
return;
129+
}
130+
const { npm } = detectPackageManager();
131+
132+
await installPackages(["@cloudflare/workers-types"], {
133+
dev: true,
134+
startText: "Installing @cloudflare/workers-types",
135+
doneText: `${brandColor("installed")} ${dim(`via ${npm}`)}`,
136+
});
137+
await updateTsConfig(ctx);
95138
}

0 commit comments

Comments
 (0)