From 1bb57d4d8d64f5fdc372a0d0b0760162c78bf398 Mon Sep 17 00:00:00 2001 From: Hasnae Date: Sat, 25 Jul 2026 15:47:56 +1000 Subject: [PATCH 1/5] add deploy with vercel button Add a "Deploy with Vercel" button to the README and a vercel.json so the clone flow builds cleanly: output points at the prerendered dist/client, framework null to avoid the SPA rewrite and use the root 404.html. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 2 ++ vercel.json | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 vercel.json diff --git a/README.md b/README.md index a0d6fc1..1ee9a37 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ A minimal starter for content-driven websites: a landing page and an MDX blog, server-rendered and statically prerendered. Fork it and make it yours. +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/labset/website-template&project-name=website-template&repository-name=website-template) + ## Stack - **React 19** + **TypeScript** diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..5305dd5 --- /dev/null +++ b/vercel.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "buildCommand": "pnpm build", + "outputDirectory": "dist/client", + "framework": null +} From 684641f3e8e17dce6da85ece804a96e9d0fab0c1 Mon Sep 17 00:00:00 2001 From: Hasnae Date: Sat, 25 Jul 2026 15:54:42 +1000 Subject: [PATCH 2/5] read SITE_URL from VITE_SITE_URL env var Replace the hardcoded SITE_URL with the VITE_SITE_URL env var (fallback https://example.com, trailing slash stripped). On Vercel, default it to the project's production domain so the Deploy button yields correct canonical/OG URLs with no config. Add .env.example and gitignore local .env files. Co-Authored-By: Claude Opus 4.8 (1M context) --- .env.example | 5 +++++ .gitignore | 5 +++++ README.md | 7 +++++-- src/lib/site.ts | 10 +++++++--- vite.config.ts | 8 ++++++++ 5 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..eb2278c --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +# Public origin used for canonical links and Open Graph / Twitter cards. +# No trailing slash. Read at build time by src/lib/site.ts. +# On Vercel this defaults to the project's production domain, so setting it is +# optional there; set it to pin a custom domain. +VITE_SITE_URL=https://example.com diff --git a/.gitignore b/.gitignore index 564eb6b..e608033 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,11 @@ dist dist-ssr *.local +# Local env files (keep the example) +.env +.env.* +!.env.example + # TanStack Router (generated) src/routeTree.gen.ts diff --git a/README.md b/README.md index 1ee9a37..40535dd 100644 --- a/README.md +++ b/README.md @@ -92,8 +92,11 @@ ships as crawlable HTML with content already in the markup, plus an explicit `src/lib/site.ts` holds `SITE_URL`, `SITE_NAME`, and `socialMeta()` (Open Graph + Twitter tags). Each route sets its own ``, description, and a -self-referencing canonical link in `head()`. **Set `SITE_URL` to your deployed -origin** before shipping. +self-referencing canonical link in `head()`. `SITE_URL` comes from the +**`VITE_SITE_URL`** env var (see `.env.example`) — set it to your deployed +origin before shipping. On Vercel it defaults to the project's production +domain, so deploys via the button above work out of the box; set +`VITE_SITE_URL` to pin a custom domain. ## Development diff --git a/src/lib/site.ts b/src/lib/site.ts index 65e7749..afe5d05 100644 --- a/src/lib/site.ts +++ b/src/lib/site.ts @@ -1,7 +1,11 @@ // Shared site-wide constants used for canonical URLs and social cards. -// Change SITE_URL to your deployed origin. No trailing slash; build paths as -// `${SITE_URL}/blog/...`. -export const SITE_URL = 'https://example.com' +// SITE_URL comes from the VITE_SITE_URL env var (set it to your deployed +// origin); on Vercel it defaults to the project's production domain — see +// vite.config.ts. Falls back to https://example.com when unset. Any trailing +// slash is stripped so paths build cleanly as `${SITE_URL}/blog/...`. +export const SITE_URL = ( + import.meta.env.VITE_SITE_URL ?? 'https://example.com' +).replace(/\/+$/, '') export const SITE_NAME = 'website-template' export const SITE_DESCRIPTION = 'A minimal starter built with TanStack Start, React, Tailwind, and shadcn — server-rendered, type-safe, and ready to grow.' diff --git a/vite.config.ts b/vite.config.ts index 8beb961..ca8c357 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,6 +5,14 @@ import tailwindcss from '@tailwindcss/vite' import mdx from '@mdx-js/rollup' import path from 'path' +// Default the public site origin to the Vercel production domain when +// VITE_SITE_URL isn't set explicitly, so the "Deploy with Vercel" button +// produces correct canonical/OG URLs with no configuration. An explicit +// VITE_SITE_URL always wins. See src/lib/site.ts. +if (!process.env.VITE_SITE_URL && process.env.VERCEL_PROJECT_PRODUCTION_URL) { + process.env.VITE_SITE_URL = `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}` +} + // https://vite.dev/config/ export default defineConfig({ plugins: [ From 3689c97910f584e418780409e218366232b70076 Mon Sep 17 00:00:00 2001 From: Hasnae <hasnae@labset.org> Date: Sat, 25 Jul 2026 16:01:11 +1000 Subject: [PATCH 3/5] add cloudflare deploy options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a "Deploy to Cloudflare" (Workers) button and wrangler.jsonc — an assets-only Worker serving dist/client with 404-page handling. Document all deploy targets in a new Deploy section, including manual Cloudflare Pages setup (the one-click button is Workers-only). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- README.md | 21 +++++++++++++++++++++ wrangler.jsonc | 13 +++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 wrangler.jsonc diff --git a/README.md b/README.md index 40535dd..18a4696 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ A minimal starter for content-driven websites: a landing page and an MDX blog, server-rendered and statically prerendered. Fork it and make it yours. [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/labset/website-template&project-name=website-template&repository-name=website-template) +[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/labset/website-template) + +See [Deploy](#deploy) for details, including Cloudflare Pages. ## Stack @@ -88,6 +91,24 @@ ships as crawlable HTML with content already in the markup, plus an explicit `/404`. The build writes static assets to `dist/client/` and the SSR runtime to `dist/server/`; deploy `dist/client/` for a static host. +## Deploy + +The output in `dist/client/` is plain static files, so any static host works. +The build command is `pnpm build` and the publish directory is `dist/client`. +Set `VITE_SITE_URL` to your origin (see [SEO](#seo)). + +- **Vercel** — click the button above, or import the repo. Config lives in + `vercel.json` (`outputDirectory: dist/client`, `framework: null`). +- **Cloudflare Workers** — click the button above. Config lives in + `wrangler.jsonc` as an assets-only Worker (no server code) serving + `dist/client`, with `not_found_handling: "404-page"` for the prerendered + `404.html`. Cloudflare runs `pnpm build`, then `wrangler deploy`. +- **Cloudflare Pages** — no one-click button (Cloudflare's deploy button is + Workers-only). In the dashboard, **Create → Pages → Connect to Git**, then set + **Build command** `pnpm build` and **Build output directory** `dist/client` + (Framework preset: none). Pages serves `404.html` automatically. `wrangler.jsonc` + is not used by Pages. + ## SEO `src/lib/site.ts` holds `SITE_URL`, `SITE_NAME`, and `socialMeta()` (Open Graph diff --git a/wrangler.jsonc b/wrangler.jsonc new file mode 100644 index 0000000..897908a --- /dev/null +++ b/wrangler.jsonc @@ -0,0 +1,13 @@ +{ + // Cloudflare Workers config for serving the prerendered static site. + // Used by the "Deploy to Cloudflare" button and `wrangler deploy`. No Worker + // script (`main`) is needed — this is an assets-only Worker. Cloudflare runs + // the `build` script from package.json, then serves ./dist/client. + "name": "website-template", + "compatibility_date": "2026-07-25", + "assets": { + "directory": "./dist/client", + // Serve the prerendered dist/client/404.html for unmatched URLs. + "not_found_handling": "404-page" + } +} From 23d88ba68f51306c4257855d0660a173d4d4d889 Mon Sep 17 00:00:00 2001 From: Hasnae <hasnae@labset.org> Date: Mon, 27 Jul 2026 09:47:00 +1000 Subject: [PATCH 4/5] split deploy buttons into per-provider sections Move each deploy button onto its own line under a per-provider subsection (Vercel, Cloudflare Workers, Cloudflare Pages) so the differently sized button badges no longer sit misaligned side by side. Replace the stacked buttons at the top with a pointer to the Deploy section. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- README.md | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 18a4696..a6476ca 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,8 @@ A minimal starter for content-driven websites: a landing page and an MDX blog, server-rendered and statically prerendered. Fork it and make it yours. -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/labset/website-template&project-name=website-template&repository-name=website-template) -[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/labset/website-template) - -See [Deploy](#deploy) for details, including Cloudflare Pages. +One click to your own copy — see [Deploy](#deploy) for Vercel, Cloudflare +Workers, and Cloudflare Pages. ## Stack @@ -94,20 +92,31 @@ ships as crawlable HTML with content already in the markup, plus an explicit ## Deploy The output in `dist/client/` is plain static files, so any static host works. -The build command is `pnpm build` and the publish directory is `dist/client`. -Set `VITE_SITE_URL` to your origin (see [SEO](#seo)). - -- **Vercel** — click the button above, or import the repo. Config lives in - `vercel.json` (`outputDirectory: dist/client`, `framework: null`). -- **Cloudflare Workers** — click the button above. Config lives in - `wrangler.jsonc` as an assets-only Worker (no server code) serving - `dist/client`, with `not_found_handling: "404-page"` for the prerendered - `404.html`. Cloudflare runs `pnpm build`, then `wrangler deploy`. -- **Cloudflare Pages** — no one-click button (Cloudflare's deploy button is - Workers-only). In the dashboard, **Create → Pages → Connect to Git**, then set - **Build command** `pnpm build` and **Build output directory** `dist/client` - (Framework preset: none). Pages serves `404.html` automatically. `wrangler.jsonc` - is not used by Pages. +Everywhere, the **build command** is `pnpm build` and the **publish directory** +is `dist/client`. Set `VITE_SITE_URL` to your origin (see [SEO](#seo)). + +### Vercel + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/labset/website-template&project-name=website-template&repository-name=website-template) + +Click the button (or import the repo). Config lives in `vercel.json` +(`outputDirectory: dist/client`, `framework: null`). + +### Cloudflare Workers + +[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/labset/website-template) + +Click the button. Config lives in `wrangler.jsonc` as an assets-only Worker (no +server code) serving `dist/client`, with `not_found_handling: "404-page"` for +the prerendered `404.html`. Cloudflare runs `pnpm build`, then `wrangler deploy`. + +### Cloudflare Pages + +No one-click button — Cloudflare's deploy button is Workers-only. In the +dashboard, **Create → Pages → Connect to Git**, then set **Build command** +`pnpm build` and **Build output directory** `dist/client` (Framework preset: +none). Pages serves `404.html` automatically. `wrangler.jsonc` is not used by +Pages. ## SEO From 34edef3ae2c312df4461a573ef87b9d81013b687 Mon Sep 17 00:00:00 2001 From: Hasnae <hasnae@labset.org> Date: Mon, 27 Jul 2026 09:57:10 +1000 Subject: [PATCH 5/5] move one-click deploy buttons to the top Put the Vercel and Cloudflare Workers buttons near the top of the README, stacked vertically under provider labels so they read clearly and don't misalign. The Deploy section keeps the config details and Cloudflare Pages setup, referencing the buttons above. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- README.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index a6476ca..05a9267 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,18 @@ A minimal starter for content-driven websites: a landing page and an MDX blog, server-rendered and statically prerendered. Fork it and make it yours. -One click to your own copy — see [Deploy](#deploy) for Vercel, Cloudflare -Workers, and Cloudflare Pages. +One click to your own copy: + +**Vercel** + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/labset/website-template&project-name=website-template&repository-name=website-template) + +**Cloudflare Workers** + +[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/labset/website-template) + +Build settings, config files, and Cloudflare Pages setup are under +[Deploy](#deploy). ## Stack @@ -97,18 +107,15 @@ is `dist/client`. Set `VITE_SITE_URL` to your origin (see [SEO](#seo)). ### Vercel -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/labset/website-template&project-name=website-template&repository-name=website-template) - -Click the button (or import the repo). Config lives in `vercel.json` +Use the button at the top (or import the repo). Config lives in `vercel.json` (`outputDirectory: dist/client`, `framework: null`). ### Cloudflare Workers -[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/labset/website-template) - -Click the button. Config lives in `wrangler.jsonc` as an assets-only Worker (no -server code) serving `dist/client`, with `not_found_handling: "404-page"` for -the prerendered `404.html`. Cloudflare runs `pnpm build`, then `wrangler deploy`. +Use the button at the top. Config lives in `wrangler.jsonc` as an assets-only +Worker (no server code) serving `dist/client`, with +`not_found_handling: "404-page"` for the prerendered `404.html`. Cloudflare runs +`pnpm build`, then `wrangler deploy`. ### Cloudflare Pages