Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
97beb67
fix(deps): update starter-peer-deps
renovate[bot] Sep 21, 2025
0b65bf4
Add cursor user rules to .gitignore.
justinvdm Sep 21, 2025
a789052
Fix esbuild scanner error after dependency updates.
justinvdm Sep 21, 2025
e85b4bd
Fix esbuild scanner error after Vite update.
justinvdm Sep 21, 2025
fb0ebd8
Fix directive scanner crashes after Vite dependency update.
justinvdm Sep 21, 2025
d8ff60a
Fix esbuild scanner error by adding outdir parameter and filtering vi…
justinvdm Sep 21, 2025
aefff20
Fix esbuild scanner error and TypeScript type compatibility issues.
justinvdm Sep 21, 2025
f8ad318
Fix esbuild scanner error and type compatibility issues.
justinvdm Sep 21, 2025
6896d7f
Update peer dependencies to allow for canary versions.
justinvdm Sep 22, 2025
176613a
Merge branch 'main' into renovate/starter-peer-deps
justinvdm Sep 22, 2025
fd4162a
Update react and react-dom dependencies to latest canary versions.
justinvdm Sep 22, 2025
6a54ef8
Fix esbuild scanner error and CI starter checks.
justinvdm Sep 22, 2025
3b2de8a
Remove workflow for checking starters.
justinvdm Sep 22, 2025
5a02383
Merge branch 'main' into renovate/starter-peer-deps
justinvdm Sep 22, 2025
c2d9e1e
Fix esbuild scanner error and Document component types.
justinvdm Sep 22, 2025
c616cf2
Fix esbuild scanner error and ensure clean npm installation in tests.
justinvdm Sep 22, 2025
784a13f
Update vite import to include Plugin type.
justinvdm Sep 22, 2025
68e7cad
Fix esbuild scanner error and update CI workflows.
justinvdm Sep 22, 2025
6deff86
Refactor code duplication and add tarball support.
justinvdm Sep 22, 2025
896c2cc
Revert Document component type changes.
justinvdm Sep 22, 2025
1d1f7b4
Add vitest as a dependency.
justinvdm Sep 22, 2025
1c3bad1
Fix type check logging and handling.
justinvdm Sep 22, 2025
346ded8
Fix esbuild scanner error and strengthen CI process.
justinvdm Sep 22, 2025
338c4e4
Add vitest to pnpm-lock.yaml
justinvdm Sep 22, 2025
6e9b514
Remove testType and replace with tarballPath.
justinvdm Sep 22, 2025
863ea3d
Remove unused dependencies and refactor code to improve performance.
justinvdm Sep 22, 2025
ac047a2
Add support for creating and cleaning up SDK tarballs.
justinvdm Sep 22, 2025
c1caa4a
Update fs-extra imports to include existsSync.
justinvdm Sep 22, 2025
e647066
Fix npm pack command to use stdio pipe.
justinvdm Sep 22, 2025
859f7f1
Enable appending of frozen-lockfile=false to .npmrc in copyProjectToT…
justinvdm Sep 22, 2025
95d03b7
Disable hardened mode for yarn installation.
justinvdm Sep 22, 2025
6974769
Remove yarn immutable flag and disable hardened mode.
justinvdm Sep 22, 2025
40a5c1d
Disable hardened mode for yarn installation.
justinvdm Sep 22, 2025
495ee1b
Merge branch 'main' into renovate/starter-peer-deps
justinvdm Sep 22, 2025
38c55bf
Merge branch 'main' into renovate/starter-peer-deps
justinvdm Sep 22, 2025
8968c32
Merge branch 'main' into renovate/starter-peer-deps
justinvdm Sep 22, 2025
784770e
Fix inlineDynamicImports option with multiple inputs error.
justinvdm Sep 22, 2025
1db2934
Fix Cloudflare plugin and Rollup incompatibility.
justinvdm Sep 22, 2025
108f937
Revert SSR build configuration change.
justinvdm Sep 22, 2025
e0a9dc0
Fix directive scanner entry point for dev mode.
justinvdm Sep 22, 2025
4b83813
Add worker entry pathname to buildApp function.
justinvdm Sep 22, 2025
1f51d12
Remove debug import.
justinvdm Sep 22, 2025
7568e06
Fix esbuild scanner errors and build process conflicts.
justinvdm Sep 22, 2025
b4b6185
Fix esbuild scanner error and update CI infrastructure to use tarball…
justinvdm Sep 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 0 additions & 45 deletions .github/workflows/check-starters.yml

This file was deleted.

4 changes: 4 additions & 0 deletions .github/workflows/playground-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ on:
- main
paths-ignore:
- "docs/**"
- ".notes/**"
- "*.md"
pull_request:
branches:
- main
paths-ignore:
- "docs/**"
- ".notes/**"
- "*.md"
workflow_dispatch:
inputs:
os:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/smoke-test-starters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ on:
- main
paths-ignore:
- "docs/**"
- ".notes/**"
- "*.md"
pull_request:
branches:
- main
paths-ignore:
- "docs/**"
- ".notes/**"
- "*.md"
workflow_dispatch:
inputs:
starter:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,5 @@ smoke-test-artifacts
# But we also don't want to commit the cursor rules to this repo
starters/standard/.cursor/rules/*
starters/standard/.pnpm-store

.cursor/rules/user
290 changes: 290 additions & 0 deletions .notes/justin/worklogs/2025-09-21-fix-esbuild-scanner-error.md

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions .notes/justin/worklogs/205-09-21-fix-esbuild-scanner-error.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Running the type check separately was problematic because it would run before the necessary types had been generated. Relying on the `generate` script's built-in type check ensures that types are checked at the correct point in the process, resolving the CI failures.

## PR Description

### Manual Changes and Fixes

This PR includes manual changes to address issues that arose from the automated dependency updates.

#### Problem

The dependency updates, primarily to Vite and its internal esbuild version, introduced several breaking changes and revealed weaknesses in the CI process:

1. **Build Failures**: An esbuild version bump caused a breaking change in its API, leading to build failures in the directive scanner.
2. **CI Blind Spots**: The existing CI (`check-starters.yml`) used workspace linking, which masked type inconsistencies and did not accurately simulate a real user's package installation. This allowed type errors related to Vite's updated plugin API to go undetected.
3. **Brittle Test Environments**: Attempts to improve CI by running `npm run check` in isolated environments failed. This was due to broken `pnpm` symlinks being copied into test directories, which prevented clean dependency installation.
4. **Code Duplication**: The setup logic for smoke tests and the E2E tests was heavily duplicated, making maintenance difficult.

#### Solution

A series of fixes and refactorings were implemented to resolve these issues and make the testing process more robust:

1. **Build Fixes**: The esbuild scanner was updated to be compatible with the new API. A TypeScript error in an E2E test file related to `null` values was also corrected.
2. **Tarball-Based Testing**: The CI process was refactored to use tarball-based installations for E2E and smoke tests. This more accurately reflects a real user environment and successfully caught the underlying type errors.
3. **Test Environment Refactoring**: The project-copying and environment setup logic for both smoke and E2E tests were consolidated into a single, shared, cross-platform function. This new function correctly excludes `node_modules` to ensure clean dependency installs, resolving the broken symlink issue.
4. **Simplified Type Checking**: Redundant `npm run check` commands were removed from the test harnesses. The type check that runs as part of the `npm run generate` command is now the single source of truth, ensuring types are checked only after they have been correctly generated.

These changes ensure the codebase is compatible with the updated dependencies and strengthen the CI process to prevent similar issues in the future.
15 changes: 8 additions & 7 deletions playground/hello-world/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,20 @@
},
"dependencies": {
"rwsdk": "workspace:*",
"react": "19.2.0-canary-3fb190f7-20250908",
"react-dom": "19.2.0-canary-3fb190f7-20250908",
"react-server-dom-webpack": "19.2.0-canary-3fb190f7-20250908"
"react": "19.2.0-canary-d415fd3e-20250919",
"react-dom": "19.2.0-canary-d415fd3e-20250919",
"react-server-dom-webpack": "19.2.0-canary-d415fd3e-20250919"
},
"devDependencies": {
"@cloudflare/vite-plugin": "1.12.4",
"@cloudflare/workers-types": "4.20250913.0",
"@cloudflare/vite-plugin": "1.13.3",
"@cloudflare/workers-types": "4.20250921.0",
"@types/node": "22.14.0",
"@types/react": "19.1.2",
"@types/react-dom": "19.1.2",
"typescript": "5.8.3",
"vite": "7.1.5",
"wrangler": "4.35.0"
"vite": "7.1.6",
"vitest": "^3.1.1",
"wrangler": "4.38.0"
},
"pnpm": {
"onlyBuiltDependencies": [
Expand Down
117 changes: 104 additions & 13 deletions playground/hello-world/worker-configuration.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
/* eslint-disable */
// Generated by Wrangler by running `wrangler types` (hash: 187132f48ddf0f604882ba8213fe386f)
// Runtime types generated with workerd@1.20250906.0 2025-08-21 nodejs_compat
// Generated by Wrangler by running `wrangler types` (hash: 6b6db21c80ba9cfeb812f12bd8b8b3e4)
// Runtime types generated with workerd@1.20250917.0 2025-08-21 nodejs_compat
declare namespace Cloudflare {
interface GlobalProps {
mainModule: typeof import("./src/worker");
}
interface Env {
ASSETS: Fetcher;
}
Expand Down Expand Up @@ -340,10 +343,10 @@ declare const origin: string;
declare const navigator: Navigator;
interface TestController {
}
interface ExecutionContext {
interface ExecutionContext<Props = unknown> {
waitUntil(promise: Promise<any>): void;
passThroughOnException(): void;
props: any;
readonly props: Props;
}
type ExportedHandlerFetchHandler<Env = unknown, CfHostMetadata = unknown> = (request: Request<CfHostMetadata, IncomingRequestCfProperties<CfHostMetadata>>, env: Env, ctx: ExecutionContext) => Response | Promise<Response>;
type ExportedHandlerTailHandler<Env = unknown> = (events: TraceItem[], env: Env, ctx: ExecutionContext) => void | Promise<void>;
Expand Down Expand Up @@ -430,9 +433,11 @@ type DurableObjectLocationHint = "wnam" | "enam" | "sam" | "weur" | "eeur" | "ap
interface DurableObjectNamespaceGetDurableObjectOptions {
locationHint?: DurableObjectLocationHint;
}
interface DurableObjectState {
interface DurableObjectClass<_T extends Rpc.DurableObjectBranded | undefined = undefined> {
}
interface DurableObjectState<Props = unknown> {
waitUntil(promise: Promise<any>): void;
props: any;
readonly props: Props;
readonly id: DurableObjectId;
readonly storage: DurableObjectStorage;
container?: Container;
Expand Down Expand Up @@ -2569,6 +2574,17 @@ declare class MessageChannel {
interface MessagePortPostMessageOptions {
transfer?: any[];
}
type LoopbackForExport<T extends (new (...args: any[]) => Rpc.EntrypointBranded) | ExportedHandler<any, any, any> | undefined = undefined> = T extends new (...args: any[]) => Rpc.WorkerEntrypointBranded ? LoopbackServiceStub<InstanceType<T>> : T extends new (...args: any[]) => Rpc.DurableObjectBranded ? LoopbackDurableObjectClass<InstanceType<T>> : T extends ExportedHandler<any, any, any> ? LoopbackServiceStub<undefined> : undefined;
type LoopbackServiceStub<T extends Rpc.WorkerEntrypointBranded | undefined = undefined> = Fetcher<T> & (T extends CloudflareWorkersModule.WorkerEntrypoint<any, infer Props> ? (opts: {
props?: Props;
}) => Fetcher<T> : (opts: {
props?: any;
}) => Fetcher<T>);
type LoopbackDurableObjectClass<T extends Rpc.DurableObjectBranded | undefined = undefined> = DurableObjectClass<T> & (T extends CloudflareWorkersModule.DurableObject<any, infer Props> ? (opts: {
props?: Props;
}) => DurableObjectClass<T> : (opts: {
props?: any;
}) => DurableObjectClass<T>);
interface SyncKvStorage {
get<T = unknown>(key: string): T | undefined;
list<T = unknown>(options?: SyncKvListOptions): Iterable<[
Expand All @@ -2586,6 +2602,34 @@ interface SyncKvListOptions {
reverse?: boolean;
limit?: number;
}
interface WorkerStub {
getEntrypoint<T extends Rpc.WorkerEntrypointBranded | undefined>(name?: string, options?: WorkerStubEntrypointOptions): Fetcher<T>;
}
interface WorkerStubEntrypointOptions {
props?: any;
}
interface WorkerLoader {
get(name: string, getCode: () => WorkerLoaderWorkerCode | Promise<WorkerLoaderWorkerCode>): WorkerStub;
}
interface WorkerLoaderModule {
js?: string;
cjs?: string;
text?: string;
data?: ArrayBuffer;
json?: any;
py?: string;
}
interface WorkerLoaderWorkerCode {
compatibilityDate: string;
compatibilityFlags?: string[];
allowExperimental?: boolean;
mainModule: string;
modules: Record<string, WorkerLoaderModule | string>;
env?: any;
globalOutbound?: (Fetcher | null);
tails?: Fetcher[];
streamingTails?: Fetcher[];
}
type AiImageClassificationInput = {
image: number[];
};
Expand Down Expand Up @@ -6305,6 +6349,11 @@ interface D1Meta {
*/
sql_duration_ms: number;
};
/**
* Number of total attempts to execute the query, due to automatic retries.
* Note: All other fields in the response like `timings` only apply to the last attempt.
*/
total_attempts?: number;
}
interface D1Response {
success: true;
Expand All @@ -6322,11 +6371,11 @@ type D1SessionConstraint =
// Indicates that the first query should go to the primary, and the rest queries
// using the same D1DatabaseSession will go to any replica that is consistent with
// the bookmark maintained by the session (returned by the first query).
"first-primary"
'first-primary'
// Indicates that the first query can go anywhere (primary or replica), and the rest queries
// using the same D1DatabaseSession will go to any replica that is consistent with
// the bookmark maintained by the session (returned by the first query).
| "first-unconstrained";
| 'first-unconstrained';
type D1SessionBookmark = string;
declare abstract class D1Database {
prepare(query: string): D1PreparedStatement;
Expand Down Expand Up @@ -6951,8 +7000,47 @@ declare namespace Rpc {
};
}
declare namespace Cloudflare {
// Type of `env`.
//
// The specific project can extend `Env` by redeclaring it in project-specific files. Typescript
// will merge all declarations.
//
// You can use `wrangler types` to generate the `Env` type automatically.
interface Env {
}
// Project-specific parameters used to inform types.
//
// This interface is, again, intended to be declared in project-specific files, and then that
// declaration will be merged with this one.
//
// A project should have a declaration like this:
//
// interface GlobalProps {
// // Declares the main module's exports. Used to populate Cloudflare.Exports aka the type
// // of `ctx.exports`.
// mainModule: typeof import("my-main-module");
//
// // Declares which of the main module's exports are configured with durable storage, and
// // thus should behave as Durable Object namsepace bindings.
// durableNamespaces: "MyDurableObject" | "AnotherDurableObject";
// }
//
// You can use `wrangler types` to generate `GlobalProps` automatically.
interface GlobalProps {
}
// Evaluates to the type of a property in GlobalProps, defaulting to `Default` if it is not
// present.
type GlobalProp<K extends string, Default> = K extends keyof GlobalProps ? GlobalProps[K] : Default;
// The type of the program's main module exports, if known. Requires `GlobalProps` to declare the
// `mainModule` property.
type MainModule = GlobalProp<"mainModule", {}>;
// The type of ctx.exports, which contains loopback bindings for all top-level exports.
type Exports = {
[K in keyof MainModule]: LoopbackForExport<MainModule[K]>
// If the export is listed in `durableNamespaces`, then it is also a
// DurableObjectNamespace.
& (K extends GlobalProp<"durableNamespaces", never> ? MainModule[K] extends new (...args: any[]) => infer DoInstance ? DoInstance extends Rpc.DurableObjectBranded ? DurableObjectNamespace<DoInstance> : DurableObjectNamespace<undefined> : DurableObjectNamespace<undefined> : {});
};
}
declare module 'cloudflare:node' {
export interface DefaultHandler {
Expand All @@ -6967,7 +7055,7 @@ declare module 'cloudflare:node' {
port: number;
}, handlers?: Omit<DefaultHandler, 'fetch'>): DefaultHandler;
}
declare module 'cloudflare:workers' {
declare namespace CloudflareWorkersModule {
export type RpcStub<T extends Rpc.Stubable> = Rpc.Stub<T>;
export const RpcStub: {
new <T extends Rpc.Stubable>(value: T): Rpc.Stub<T>;
Expand All @@ -6976,9 +7064,9 @@ declare module 'cloudflare:workers' {
[Rpc.__RPC_TARGET_BRAND]: never;
}
// `protected` fields don't appear in `keyof`s, so can't be accessed over RPC
export abstract class WorkerEntrypoint<Env = unknown> implements Rpc.WorkerEntrypointBranded {
export abstract class WorkerEntrypoint<Env = Cloudflare.Env, Props = {}> implements Rpc.WorkerEntrypointBranded {
[Rpc.__WORKER_ENTRYPOINT_BRAND]: never;
protected ctx: ExecutionContext;
protected ctx: ExecutionContext<Props>;
protected env: Env;
constructor(ctx: ExecutionContext, env: Env);
fetch?(request: Request): Response | Promise<Response>;
Expand All @@ -6988,9 +7076,9 @@ declare module 'cloudflare:workers' {
queue?(batch: MessageBatch<unknown>): void | Promise<void>;
test?(controller: TestController): void | Promise<void>;
}
export abstract class DurableObject<Env = unknown> implements Rpc.DurableObjectBranded {
export abstract class DurableObject<Env = Cloudflare.Env, Props = {}> implements Rpc.DurableObjectBranded {
[Rpc.__DURABLE_OBJECT_BRAND]: never;
protected ctx: DurableObjectState;
protected ctx: DurableObjectState<Props>;
protected env: Env;
constructor(ctx: DurableObjectState, env: Env);
fetch?(request: Request): Response | Promise<Response>;
Expand Down Expand Up @@ -7043,6 +7131,9 @@ declare module 'cloudflare:workers' {
export function waitUntil(promise: Promise<unknown>): void;
export const env: Cloudflare.Env;
}
declare module 'cloudflare:workers' {
export = CloudflareWorkersModule;
}
interface SecretsStoreSecret {
/**
* Get a secret from the Secrets Store, returning a string of the secret value
Expand Down
15 changes: 8 additions & 7 deletions playground/render-apis/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,20 @@
},
"dependencies": {
"rwsdk": "workspace:*",
"react": "19.2.0-canary-3fb190f7-20250908",
"react-dom": "19.2.0-canary-3fb190f7-20250908",
"react-server-dom-webpack": "19.2.0-canary-3fb190f7-20250908"
"react": "19.2.0-canary-d415fd3e-20250919",
"react-dom": "19.2.0-canary-d415fd3e-20250919",
"react-server-dom-webpack": "19.2.0-canary-d415fd3e-20250919"
},
"devDependencies": {
"@cloudflare/vite-plugin": "1.12.4",
"@cloudflare/workers-types": "4.20250913.0",
"@cloudflare/vite-plugin": "1.13.3",
"@cloudflare/workers-types": "4.20250921.0",
"@types/node": "22.14.0",
"@types/react": "19.1.2",
"@types/react-dom": "19.1.2",
"typescript": "5.8.3",
"vite": "7.1.5",
"wrangler": "4.35.0"
"vite": "7.1.6",
"vitest": "^3.1.1",
"wrangler": "4.38.0"
},
"pnpm": {
"onlyBuiltDependencies": [
Expand Down
4 changes: 3 additions & 1 deletion playground/useid-test/__tests__/e2e.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@ describe("useId Playground", () => {
page.evaluate((element: Element) => element.textContent, el),
),
);
return statuses.every((status: string) => status.includes("Hydrated"));
return statuses.every(
(status: string | null) => status?.includes("Hydrated") ?? false,
);
});

// Get IDs after hydration
Expand Down
Loading
Loading