Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,8 @@ jobs:
run: pnpm install --frozen-lockfile

- name: Run the Cloudflare build
# The CI artifact is discarded. Convex supplies the real deployment URL
# during development and provider builds.
env:
VITE_CONVEX_URL: http://127.0.0.1:3210
run: pnpm run build
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ vp run dev
```

The development command starts Convex and TanStack Start together. It also creates missing Convex
Auth JWT keys in the development deployment.
Auth JWT keys in the development deployment. Convex writes `VITE_CONVEX_URL` to `.env.local`; do
not set it manually.

For an isolated local agent or worktree backend, use:

Expand Down Expand Up @@ -76,7 +77,8 @@ Cloudflare Workers Builds runs `pnpm run build` for all branches. It then uses:

`scripts/build-cloudflare.ts` selects the Convex key from `WORKERS_CI_BRANCH` and fails closed when
the branch identity is missing. `scripts/verify-current-branch-head.ts` prevents an older concurrent
build from deploying backend code after a newer commit reaches the same branch.
build from deploying backend code after a newer commit reaches the same branch. `convex deploy
--cmd` supplies `VITE_CONVEX_URL` to the frontend build, so it is not a Cloudflare build variable.

See [`docs/cloudflare-workers-builds.md`](./docs/cloudflare-workers-builds.md) for the detailed build
and deploy behavior. Use the
Expand Down
3 changes: 3 additions & 0 deletions docs/cloudflare-workers-builds.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ Set these build secrets in the Cloudflare Workers Builds settings:
- `CONVEX_DEPLOY_KEY`
- `PREVIEW_CONVEX_DEPLOY_KEY`

Do not add `VITE_CONVEX_URL`. Convex supplies the selected deployment URL to the frontend command
that runs through `convex deploy --cmd`.

Cloudflare Workers Builds has separate production and preview build triggers
under the hood, but the dashboard currently shows one build-variable table. To
keep dashboard and API-created configurations equivalent, store both secrets on
Expand Down
11 changes: 8 additions & 3 deletions scripts/cloudflare-prerender-pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ export type CloudflarePrerenderPage = {
};

/**
* Public pages that TanStack Start prerenders and Cloudflare exposes through
* exact _redirects aliases. Cloudflare SPA mode owns /index.html, so / must
* use a separate output file.
* Static public pages that TanStack Start prerenders and Cloudflare exposes
* through exact _redirects aliases.
*
* Cloudflare SPA mode always uses /index.html when no asset matches. The real
* / route is also prerendered, so keep /index.html as the route-neutral shell
* and write / to /_landing.html. public/_redirects exposes that file at exact
* /. Revisit this split if Cloudflare supports a configurable SPA fallback
* file or if this app moves to request-time SSR.
*/
export const cloudflarePrerenderPages = [
{
Expand Down
12 changes: 4 additions & 8 deletions src/lib/convex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,13 @@ import { ConvexReactClient } from "convex/react";
import type { ReactNode } from "react";

const convexUrl = import.meta.env["VITE_CONVEX_URL"];
const convexClient = convexUrl ? new ConvexReactClient(convexUrl) : null;
let convexClient: ConvexReactClient | undefined;

export function ConvexClientProvider({ children }: Readonly<{ children: ReactNode }>) {
if (!convexClient) {
return (
<main className="mx-auto max-w-2xl p-4">
<h1 className="text-xl">Convex setup</h1>
<p>Set VITE_CONVEX_URL in .env.local to connect the app.</p>
</main>
);
if (!convexUrl) {
throw new Error("VITE_CONVEX_URL is required. Run a supported Samebase dev or deploy command.");
}

convexClient ??= new ConvexReactClient(convexUrl);
return <ConvexAuthProvider client={convexClient}>{children}</ConvexAuthProvider>;
}
25 changes: 11 additions & 14 deletions src/routes/__root.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { HeadContent, Link, Outlet, Scripts, createRootRoute } from "@tanstack/react-router";
import type { ReactNode } from "react";
import { ConvexClientProvider } from "../lib/convex";
import appCss from "../style.css?url";
import { Button } from "#components/ui/button";

Expand Down Expand Up @@ -31,19 +30,17 @@ export const Route = createRootRoute({
function RootComponent() {
return (
<RootDocument>
<ConvexClientProvider>
<nav className="mx-auto flex w-full max-w-2xl pt-2">
<Button asChild variant="link">
<Link to="/" activeOptions={{ exact: true }}>
Home
</Link>
</Button>
<Button asChild variant="link">
<Link to="/about">About</Link>
</Button>
</nav>
<Outlet />
</ConvexClientProvider>
<nav className="mx-auto flex w-full max-w-2xl pt-2">
<Button asChild variant="link">
<Link to="/" activeOptions={{ exact: true }}>
Home
</Link>
</Button>
<Button asChild variant="link">
<Link to="/about">About</Link>
</Button>
</nav>
<Outlet />
</RootDocument>
);
}
Expand Down
9 changes: 9 additions & 0 deletions src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { QRCodeSVG } from "qrcode.react";
import { type FormEvent, useEffect, useState } from "react";
import { api } from "../../convex/_generated/api";
import type { Id } from "../../convex/_generated/dataModel";
import { ConvexClientProvider } from "../lib/convex";
import { Button } from "#components/ui/button";
import { Checkbox } from "#components/ui/checkbox";
import { Input } from "#components/ui/input";
Expand All @@ -25,6 +26,14 @@ export const Route = createFileRoute("/")({
});

function HomePage() {
return (
<ConvexClientProvider>
<TodoPage />
</ConvexClientProvider>
);
}

function TodoPage() {
const [shareUrl, setShareUrl] = useState("");
const todoState = useQuery(api.todos.list, {});
const todos = todoState?.todos ?? [];
Expand Down