feat: wire initial Next.js app to Convex backend#65
Conversation
Greptile SummaryThis PR wires the existing Key changes:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Dev as Developer
participant Script as run-web-with-convex-env.mjs
participant EnvFile as .env.local
participant Next as Next.js (apps/web)
participant Provider as ConvexClientProvider
participant Panel as ConvexRuntimePanel
participant Convex as Convex Backend (convex/)
Dev->>Script: pnpm dev:web
Script->>EnvFile: parseEnvFile(.env.local)
EnvFile-->>Script: { CONVEX_URL, ... }
Script->>Script: bridge CONVEX_URL → NEXT_PUBLIC_CONVEX_URL
Script->>Next: spawn(pnpm --filter web dev, env)
Note over Next: SSR render
Next->>Provider: render ConvexClientProvider
Provider->>Provider: getConvexClient()<br/>(typeof window === "undefined" → null)
Provider-->>Next: children (no ConvexProvider wrap)
Next->>Panel: render ConvexRuntimePanel
Panel->>Panel: isClient = false → static placeholder
Note over Next: Client hydration
Next->>Provider: hydrate ConvexClientProvider
Provider->>Provider: getConvexClient(convexUrl)<br/>→ new ConvexReactClient
Provider-->>Next: wrap children in ConvexProvider
Next->>Panel: hydrate ConvexRuntimePanel
Panel->>Panel: isClient = true
Panel->>Panel: render ConvexQueryErrorBoundary
Panel->>Convex: useQuery(api.health.status)
Convex-->>Panel: { status, backend, project, scope, note }
Panel-->>Dev: Live status panel rendered
Prompt To Fix All With AIThis is a comment left during a code review.
Path: apps/web/README.md
Line: 9-13
Comment:
**Bootstrap step missing from primary workflow**
`pnpm dev:backend:local` is listed in the primary getting-started block, but `pnpm bootstrap:backend:local` has been moved to "Useful follow-up commands." For a first-time developer cloning the repo, running `pnpm dev:backend:local` before bootstrapping will fail because there is no local Convex deployment yet.
`docs/backend/convex-bootstrap.md` correctly sequences the steps as: install → bootstrap → dev backend → dev web. The `apps/web/README.md` should mirror that order:
```suggestion
pnpm install
pnpm bootstrap:backend:local
pnpm dev:backend:local
pnpm dev:web
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: apps/web/src/app/convex-client-provider.tsx
Line: 29-38
Comment:
**Side-effectful function called in render body**
`getConvexClient` can call `convexClient?.close()` and `new ConvexReactClient(convexUrl)` when the URL changes. Calling these side effects directly during render — rather than inside a `useEffect` or event handler — is outside React's render-purity contract. In practice the URL is a compile-time constant so the branch that mutates the singleton only runs on the very first render, but React's concurrent renderer can invoke render functions multiple times before committing (e.g. during `startTransition` or hydration), which would incorrectly attempt to close and reopen the WebSocket client on each discarded render.
A light guard would make the mutation safe:
```ts
// Only mutate when the effect is committed (client-side).
// If the URL cannot change at runtime this is low-risk today, but
// explicit side-effect isolation prevents surprises under concurrent features.
```
Consider wrapping the close/create path in `useEffect` (keyed on `convexUrl`) inside `ConvexClientProvider` rather than calling it inline in the render body.
How can I resolve this? If you propose a fix, please make it concise.Last reviewed commit: b4ecf44 |
| export function ConvexClientProvider({ children }: { children: ReactNode }) { | ||
| const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL; | ||
| const client = getConvexClient(convexUrl); | ||
|
|
||
| if (!client) { | ||
| return <>{children}</>; | ||
| } | ||
|
|
||
| return <ConvexProvider client={client}>{children}</ConvexProvider>; | ||
| } |
There was a problem hiding this comment.
Side-effectful function called in render body
getConvexClient can call convexClient?.close() and new ConvexReactClient(convexUrl) when the URL changes. Calling these side effects directly during render — rather than inside a useEffect or event handler — is outside React's render-purity contract. In practice the URL is a compile-time constant so the branch that mutates the singleton only runs on the very first render, but React's concurrent renderer can invoke render functions multiple times before committing (e.g. during startTransition or hydration), which would incorrectly attempt to close and reopen the WebSocket client on each discarded render.
A light guard would make the mutation safe:
// Only mutate when the effect is committed (client-side).
// If the URL cannot change at runtime this is low-risk today, but
// explicit side-effect isolation prevents surprises under concurrent features.Consider wrapping the close/create path in useEffect (keyed on convexUrl) inside ConvexClientProvider rather than calling it inline in the render body.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/src/app/convex-client-provider.tsx
Line: 29-38
Comment:
**Side-effectful function called in render body**
`getConvexClient` can call `convexClient?.close()` and `new ConvexReactClient(convexUrl)` when the URL changes. Calling these side effects directly during render — rather than inside a `useEffect` or event handler — is outside React's render-purity contract. In practice the URL is a compile-time constant so the branch that mutates the singleton only runs on the very first render, but React's concurrent renderer can invoke render functions multiple times before committing (e.g. during `startTransition` or hydration), which would incorrectly attempt to close and reopen the WebSocket client on each discarded render.
A light guard would make the mutation safe:
```ts
// Only mutate when the effect is committed (client-side).
// If the URL cannot change at runtime this is low-risk today, but
// explicit side-effect isolation prevents surprises under concurrent features.
```
Consider wrapping the close/create path in `useEffect` (keyed on `convexUrl`) inside `ConvexClientProvider` rather than calling it inline in the render body.
How can I resolve this? If you propose a fix, please make it concise.
Summary
apps/webConvex provider and client-side query wiring so the homepage can render the existinghealth:statusbackend payloadpnpm dev:web,pnpm typecheck:web, andpnpm build:webuse the local backend without a duplicate frontend env file#64Closes #55