react-vite
Use when building or maintaining a React single-page app with Vite — project setup, routing, state, static pre-rendered content for search engines and ads review, environment variables, testing with V
Files1
View on GitHubSKILL.mdskills/tech/react-vite/SKILL.md
GitHubReact + Vite
Default: Vite's react-ts template, React function components and hooks, React Router when there is more than one screen, Vitest + Testing Library, static hosting of dist/.
Setup
npm create vite@latest app -- --template react-ts.- Scripts:
dev,build(tsc -b && vite build),preview,test(vitest run). - Only variables prefixed
VITE_reach client code, and they are public once built. Never put secrets there.
Content that must exist without JavaScript
A client-rendered SPA ships an almost empty index.html. Crawlers, link previews and ad reviewers may see no content.
- Put a meaningful static body in
index.html(or generate static pages at build time): what the page is for, how to use it, links to articles and policy pages. Let React mount into a separate element. - Give every static page its own
<title>,description, canonical URL and Open Graph tags. - Generate
sitemap.xmlat build time from the real list of pages (and their last-modified dates from git), not by hand. - Add a build-time check that fails when a page lacks a title, description or canonical link.
State and data
- Local component state first; lift state up when two siblings need it; add a store (Context + reducer, Zustand) only for truly global state.
- Fetch with an effect plus abort controller, or a data library (TanStack Query) once caching and retries matter.
- Derive values during render instead of syncing them into extra state.
Testing
- Testing Library queries by role and label (
getByRole('button', { name: /play/i })), not by class names. - Mock network at the fetch boundary (MSW or a stub).
- One Playwright smoke test per route that fails on console errors.
Upgrades
- Upgrade
reactandreact-domtogether, and@types/react*with them; mismatched versions produce peer dependency errors (ERESOLVE). - Create React App (
react-scripts) is no longer maintained and pins old TypeScript; migrate to Vite rather than fighting its constraints. - Read the framework's migration guide for each major version; run the codemods it provides.
Verification loop
npm run build(type-check + bundle) succeeds.npm testpasses.npm run previewand view the page with JavaScript disabled: the static content is still there.- Check bundle size and the largest chunks (with a bundle visualiser such as
rollup-plugin-visualizer) after adding dependencies.
Pitfalls
- Strict mode double-invokes effects in development; an effect that breaks when run twice has a missing cleanup.
- Stale closures: handlers capturing old state; use functional updates (
setX(x => x + 1)). - Keys: use stable IDs, not array indexes, for lists that reorder.
- Client-side routes on static hosts need a fallback to
index.html(a_redirectsorstaticwebapp.config.jsonrule), or deep links return 404. - Ads and third-party scripts inside React components re-run on every mount; load them once and only on pages with real content.