Production-ready setup with tests, commit conventions, and automated CI/CD to GitHub Pages.
- Highlights
- Tech Stack
- Quick Links
- Quick Demo
- Getting Started
- Scripts
- Testing
- Linting and Formatting
- TypeScript
- Commit Conventions and Git Hooks
- CI (GitHub Actions)
- CD (GitHub Pages)
- Dependabot
- Project Structure
- Troubleshooting
- License
A professional Vite + React + TypeScript setup with unit/integration tests, E2E tests, strict linting and typing, commit conventions, and automated CI/CD.
- Strict TypeScript with enhanced safety options
- ESLint with TypeScript, React hooks, Hot Refresh, and accessibility rules
- Prettier formatting integrated with lint-staged and Husky pre-commit hooks
- Conventional Commits enforced via Commitlint
- Vitest + React Testing Library for unit/integration tests with coverage
- Playwright for E2E tests using the production preview server
- GitHub Actions: CI pipeline (lint, typecheck, unit tests + coverage, build, E2E)
- GitHub Pages deployment with correct base path
- Dependabot for weekly npm dependency updates
React+Vite+TypeScriptESLint(@typescript-eslint,eslint-plugin-react-hooks,eslint-plugin-react-refresh,eslint-plugin-jsx-a11y)PrettierVitest,@testing-library/react,@testing-library/jest-domPlaywrightHusky+lint-staged+CommitlintGitHub Actions+GitHub Pages
- Actions: Actions
- CI workflow: .github/workflows/ci.yml
- Deploy workflow: .github/workflows/deploy.yml
- Live Demo: https://casaislabs.github.io/React-CI-CD/
- Install and verify locally:
npm cinpm run lintnpm run typechecknpm run test:coveragenpx playwright installnpm run test:e2e
- Open a PR with a Conventional Commit title (e.g.,
docs: refine README header with badges and tagline). - In Actions, ensure required checks are green:
commitlint,build-and-test (20),validate-title. - Merge using “Squash and merge”; deployment runs automatically.
- Visit the site: https://casaislabs.github.io/React-CI-CD/
Prerequisites:
- Node.js
>=20and npm
Install dependencies:
npm install
Husky hooks install automatically via the prepare script. If needed, run:
npm run prepare
Start development server:
npm run dev
npm run dev— start Vite dev servernpm run build— build TypeScript project graph, then Vite production buildnpm run preview— servedistonhttp://localhost:4173npm run lint— run ESLint across the reponpm run lint:fix— auto-fix ESLint issuesnpm run typecheck— strict type checking for app and node configsnpm run format/npm run format:check— Prettier write/checknpm run test— run Vitest unit/integration testsnpm run test:coverage— Vitest with coverage (text, html, lcov)npm run test:e2e— build and run Playwright E2E tests
Unit/Integration (Vitest + Testing Library):
npm run test
npm run test:coverage
- Vitest configuration lives in
vitest.config.tswith jsdom environment, setup file, coverage reporters, and exclusions. - Extended matchers from
@testing-library/jest-domare registered insrc/test/setup.ts. - Example tests:
src/App.test.tsx— renders title and verifies counter interactionsrc/main.test.tsx— loads the app entry and checks the heading appears
E2E (Playwright):
npx playwright install
npm run test:e2e
playwright.config.tsstartsvite previewagainst the builtdist, ensuring tests run against the production build.- Example spec:
tests/e2e/app.spec.ts— validates title and counter increment.
- ESLint configuration is in
eslint.config.jswith TypeScript, React Hooks, Refresh, and a11y rules. Prettier compatibility avoids stylistic conflicts. - Prettier configuration is in
prettier.config.cjs. lint-stagedconfiguration is in.lintstagedrc.jsonto fix and format staged files on commit.
- Strict mode is enabled with additional safety options like
exactOptionalPropertyTypesandnoUncheckedIndexedAccessintsconfig.app.jsonandtsconfig.node.json. - Vitest globals are available through
types: ["vite/client", "vitest/globals"]intsconfig.app.json.
- Conventional Commits enforced with Commitlint (
commitlint.config.cjs). Examples:feat: add counter testfix: correct accessibility alt text
- Husky hooks:
.husky/pre-commitrunslint-stagedto fix/format staged files.husky/commit-msgvalidates commit messages
Workflow file: .github/workflows/ci.yml
- Triggers on
pushandpull_requesttomain/master - Steps:
- Checkout and setup Node with npm cache
- Install dependencies via
npm ci - Run
lintandtypecheck - Run unit/integration tests with coverage
- Build the project
- Install Playwright browsers and run E2E tests
- Upload coverage artifact
Workflow file: .github/workflows/deploy.yml
- On push to
main/master, builds with--base=/<repository-name>/to support GitHub Pages routing - Publishes
distviaactions/deploy-pages - After enabling Pages (Settings → Pages → Source: "GitHub Actions"), the deployment URL appears in the
deployjob output
- Open a PR: create a feature branch, push, and open a PR to
mainwith a Conventional Commit title (e.g.,chore: set up tests, CI/CD, commit hooks). - Checks on PR: CI (lint, typecheck, unit/coverage, build, E2E), Commitlint (commit messages), Semantic PR (PR title).
- Merge policy: use “Squash and merge” to keep a linear history; the final commit takes the PR title.
- Post-merge: delete the feature branch locally and on remote.
- Actions permissions: select
Allow all actions and reusable workflows. - Workflow permissions: set default
Read and write permissionsso deploy can publish Pages. - Fork pull requests: require approval for first-time contributors (recommended for public repos).
- Settings → Branches → Add rule for
main. - Require a pull request before merging.
- Require approvals: 1.
- Dismiss stale approvals when new commits are pushed.
- Require conversation resolution before merging.
- Require status checks to pass before merging:
- Required checks:
commitlint,build-and-test (20),validate-title.
- Required checks:
- Require branches to be up to date before merging.
- Require linear history.
- Do not allow bypassing the above settings; include administrators.
- Disallow force pushes and deletions on
main.
For solo maintenance, set required approvals to 0 while keeping required status checks, up‑to‑date branches, conversation resolution, and linear history.
- Enable Pages: Settings → Pages → Source: GitHub Actions.
- Trigger a deploy: merge to
mainor re‑run the “Deploy to GitHub Pages” workflow. - Find URL: open Actions → last “Deploy to GitHub Pages” run →
page_urlin thedeployjob. - Validate site: title “Vite + React”, counter button increments, assets load under
/<repository>/.
- Re‑run deploy: Actions → “Deploy to GitHub Pages” → Re‑run jobs.
- Manual trigger: push to
main(e.g., an empty commit) to start a fresh deploy:
git checkout main
git pull
git commit --allow-empty -m "chore: trigger pages deploy"
git push
- If
git pullaborts due to untrackedcoverage/ortest-results/, remove local artifacts:
# PowerShell
Remove-Item -Recurse -Force .\coverage
Remove-Item -Recurse -Force .\test-results
# or with Git
git clean -fd coverage test-results
git pull
- To stop tracking generated artifacts already in the repo:
git checkout -b chore/remove-generated-artifacts
git rm -r --cached coverage test-results
git commit -m "chore: remove generated artifacts from repo"
git push -u origin chore/remove-generated-artifacts
# open PR and merge
.github/dependabot.ymlupdates npm dependencies weekly, opening PRs automatically.
├─ src/
│ ├─ App.tsx
│ ├─ main.tsx
│ ├─ App.test.tsx
│ ├─ main.test.tsx
│ └─ test/setup.ts
├─ tests/
│ └─ e2e/app.spec.ts
├─ eslint.config.js
├─ vitest.config.ts
├─ playwright.config.ts
├─ prettier.config.cjs
├─ .lintstagedrc.json
├─ .husky/
│ ├─ pre-commit
│ └─ commit-msg
└─ .github/workflows/
├─ ci.yml
└─ deploy.yml
- Vitest runs E2E tests unexpectedly: ensure
vitest.config.tsexcludestests/e2e/**. - Missing
testglobals: ensuretypes: ["vitest/globals"]intsconfig.app.jsonand importtest/expectfromvitestwhere needed. - If Playwright browsers are missing, run
npx playwright installlocally and ensure the CI step “Install Playwright browsers” is present. - Git commit blocked: check Conventional Commit format and ESLint/Prettier errors fixed by
lint-staged.
See LICENSE for details.