Skip to content

Commit 53f5a59

Browse files
[create-cloudflare] Fix scaffolding when @cloudflare/workers-types v5 is installed (#14544)
1 parent 5d9990e commit 53f5a59

4 files changed

Lines changed: 56 additions & 10 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"create-cloudflare": patch
3+
---
4+
5+
Fix scaffolding of Qwik projects when `@cloudflare/workers-types` v5 is installed
6+
7+
`@cloudflare/workers-types` v5 removed the date-versioned entrypoints (e.g. `@cloudflare/workers-types/2024-01-01`) in favour of a single bare package import. C3 previously only added a date-versioned entrypoint to `tsconfig.json` and skipped updating the config entirely when none could be found, leaving templates that install workers-types (such as Qwik) without any Cloudflare types.
8+
9+
C3 now falls back to adding the bare `@cloudflare/workers-types` entry when no date-versioned entrypoint is available, so the correct types are always configured regardless of the installed version.

packages/create-cloudflare/e2e/helpers/framework-helpers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,13 +367,13 @@ export async function verifyTypes(
367367
return;
368368
}
369369

370-
const tsconfigTypes = tsconfig.compilerOptions?.types;
370+
const tsconfigTypes: string[] = tsconfig.compilerOptions?.types ?? [];
371371
if (workersTypes === "generated") {
372372
expect(tsconfigTypes).toContain(typesPath);
373373
}
374374
if (workersTypes === "installed") {
375375
expect(
376-
tsconfigTypes.some((x: string) => x.includes("@cloudflare/workers-types"))
376+
tsconfigTypes.some((x) => x.includes("@cloudflare/workers-types"))
377377
).toBe(true);
378378
}
379379
if (nodeCompat) {

packages/create-cloudflare/src/__tests__/workers.test.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,37 @@ describe("updateTsConfig", () => {
5353
expect(writeFile).not.toHaveBeenCalled();
5454
});
5555

56-
test("latest entrypoint not found", async ({ expect }) => {
56+
test("falls back to bare workers-types when no date-versioned entrypoint is available", async ({
57+
expect,
58+
}) => {
5759
ctx.template.workersTypes = "installed";
5860

61+
// `@cloudflare/workers-types` v5+ has no date-versioned entrypoints, but the
62+
// package (mocked as existing via existsSync) is still installed.
5963
vi.mocked(getLatestTypesEntrypoint).mockReturnValue(null);
6064
await updateTsConfig(ctx, { usesNodeCompat: false });
6165

62-
expect(writeFile).not.toHaveBeenCalled();
66+
const written = vi.mocked(writeFile).mock.calls[0][1];
67+
expect(written).toContain(`"@cloudflare/workers-types"`);
68+
expect(written).not.toContain(`@cloudflare/workers-types/`);
69+
});
70+
71+
test("does not add bare workers-types when the package is not installed", async ({
72+
expect,
73+
}) => {
74+
ctx.template.workersTypes = "installed";
75+
vi.mocked(getLatestTypesEntrypoint).mockReturnValue(null);
76+
vi.mocked(readFile).mockImplementation(
77+
() => `{ "compilerOptions": { "types": [] } }`
78+
);
79+
// tsconfig.json exists, but node_modules/@cloudflare/workers-types does not.
80+
vi.mocked(existsSync).mockImplementation((p) =>
81+
String(p).includes("tsconfig.json")
82+
);
83+
await updateTsConfig(ctx, { usesNodeCompat: false });
84+
85+
const written = vi.mocked(writeFile).mock.calls[0][1];
86+
expect(written).not.toContain("@cloudflare/workers-types");
6387
});
6488

6589
test("don't clobber existing entrypoints", async ({ expect }) => {

packages/create-cloudflare/src/workers.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,18 +116,31 @@ export async function updateTsConfig(
116116
let newTypes = new Set(currentTypes);
117117
if (ctx.template.workersTypes === "installed") {
118118
const entrypointVersion = getLatestTypesEntrypoint(ctx);
119-
if (entrypointVersion === null) {
120-
return;
121-
}
122-
const typesEntrypoint = `@cloudflare/workers-types/${entrypointVersion}`;
123119
const explicitEntrypoint = currentTypes.some((t) =>
124120
t.match(/@cloudflare\/workers-types\/\d{4}-\d{2}-\d{2}/)
125121
);
126122
// If a type declaration with an explicit entrypoint exists, leave the types as is.
127-
// Otherwise, add the latest entrypoint
123+
// Otherwise add the workers-types entry:
124+
// - `@cloudflare/workers-types` v4 and earlier ship date-versioned entrypoints,
125+
// so use the latest one (e.g. `@cloudflare/workers-types/2024-01-01`).
126+
// - v5+ dropped the date-versioned entrypoints (getLatestTypesEntrypoint returns
127+
// null), so fall back to the bare package import when it is actually installed.
128128
if (!explicitEntrypoint) {
129129
newTypes.delete("@cloudflare/workers-types");
130-
newTypes.add(typesEntrypoint);
130+
if (entrypointVersion !== null) {
131+
newTypes.add(`@cloudflare/workers-types/${entrypointVersion}`);
132+
} else if (
133+
existsSync(
134+
join(
135+
ctx.project.path,
136+
"node_modules",
137+
"@cloudflare",
138+
"workers-types"
139+
)
140+
)
141+
) {
142+
newTypes.add("@cloudflare/workers-types");
143+
}
131144
}
132145
} else if (ctx.template.workersTypes === "generated") {
133146
newTypes.add(ctx.template.typesPath ?? "./worker-configuration.d.ts");

0 commit comments

Comments
 (0)