Opinionated starter for React + Redux Saga apps. One static build deploys to either GitHub Pages or a Cloudflare Worker (Static Assets) with no code changes.
- React 19 + React Router 7
(
BrowserRouter, basename follows the deploy base path) - Redux Toolkit + redux-saga via typed-redux-saga (typed effects)
- Tailwind CSS 4 (via
@tailwindcss/vite) - Vite 7 (dev, build, preview, Vitest)
- TypeScript strict
- Biome for lint + format, including the shared
no-casts/component-decl/fc-propsGritQL plugins inbiome/and theredux-saga/effects→typed-redux-sagaimport rule - Vitest + Testing Library for tests
- Yarn 4 (
node-moduleslinker)
yarn dev # Vite dev server
yarn build # Static build for Workers (base /)
yarn build:pages # Static build for GH Pages (base /<repo>/ + 404.html)
yarn preview # Preview the Workers build locally
yarn preview:worker # Serve the build through the Worker locally
yarn deploy:worker # Deploy build to Cloudflare Workers
yarn lint # Biome check
yarn fix # Biome check + autofix
yarn typecheck # tsc --noEmit (app)
yarn test # Vitest run
yarn check # lint + typecheck + testBoth targets serve the same dist/ output. The only difference is the base
path: / on Workers, /<repo>/ on GH Pages. The router reads it from
import.meta.env.BASE_URL, so no code changes are needed per target.
yarn build:pages builds with VITE_BASE=/typescript-react-starter-kit/ and
copies dist/index.html → dist/404.html (GH Pages has no SPA fallback, so
deep links are served through the 404 page). .github/workflows/pages.yml
builds and deploys on every push to master. If you fork under a different
repo name, update VITE_BASE in build:pages and the BrowserRouter keeps
working untouched.
workers/wrangler.jsonc is a plain Worker + Static Assets config
(not_found_handling: single-page-application). workers/src/index.ts
answers /api/* (currently a 501 stub slot for a future API) and serves the
static build for everything else. .github/workflows/workers.yml builds and
deploys on every push to master; it needs CLOUDFLARE_API_TOKEN +
CLOUDFLARE_ACCOUNT_ID secrets.
An exercise tracker with three routes (/, /tracker, /about) showing
slices + sagas (persist to localStorage, fetch version over HTTP), a Zod
validated form, and schedule tables derived from the store.
- Imports from
src/use the~/prefix (tsconfig paths + Vite alias) - Components are
const Foo: FC<FooProps>with named prop interfaces - No
ascasts — narrow or validate (Zod) instead - Saga effects import from
typed-redux-saga, neverredux-saga/effects - Tabs, single quotes, no semicolons (enforced by Biome)