This guide will give you all the instructions needed to set up a React.js project with git, npm, VSCode, TypeScript, Vite, Vitest, Testing Library, ESLint, commitlint, husky, GitHub Actions CI/CD, Vercel and auto semantic releases.
I recommend to follow these instructions in the order but I made them as independent as possible so you could skip one if you wanted to without struggling too much.
You may want to fork the already setup project here:
https://github.com/NicolasBuecher/react-vite-typescript-starter-project
TODO: Maybe add instructions for Docker, Storybook, CSS frameworks?
- Why Vite?
- Initialize a git repository
- Initialize a React + Vite + TypeScript project
- Create a README.md file
- Configure ESLint
- Configure VSCode auto format
- Configure Vitest
- Configure git hooks with husky
- Create a CI/CD GitHub Actions workflow
- Deploy your project on Vercel
Vite is a frontend dev/build tool based on Rollup module bundler which leverages the availability of native ES modules in the browser to improve the development experience.
In short: it's fast and we like that.
Next.js already has its own dev/build tools based on SWC compiler and bundler, they would overlap.
Vite is like CRA, but faster. No complicated features are provided. Pick it if you don't really mind about SEO, SSR or SSG.
Otherwise, I suggest you to take a look at my React + Next + TypeScript guide.
git init
git commit --allow-empty -m "Initial commit"
In parallel you can create a new remote repository on GitHub at https://github.com/new.
And then link your local repository to your remote repository:
git branch -M main
git remote add origin git@github.com:<USER_NAME>/<REPOSITORY_NAME>.git
git push -u origin main
npm create vite@latest . -- --template react-ts
npm install
Commit your changes:
git add .
git commit -m "build: Initialize react project"
Create a README.md
file at the root of the project.
Commit your changes:
git add README.md
git commit -m "docs: Create readme file"
The common way to initialize an ESLint configuration is to run the command:
npm init @eslint/config
But it currently sucks. I recommend you to copy/paste this optimized .eslintrc.json
file at the root of your project. This is an opinionated configuration, you may remove the rules
part to stick to the most conventional rules.
In this case, you also need to install the config dependencies:
npx install-peerdeps --dev eslint-config-airbnb
npx install-peerdeps --dev eslint-config-airbnb-typescript
npm install --save-dev eslint-plugin-testing-library
Add a .eslintignore
file at the root of your project:
node_modules
dist
Update your package.json
with a lint
script:
"scripts": {
"lint": "eslint 'src/**/*.ts{,x}'",
"lint:fix": "npm run lint -- --fix"
}
You may format your code following your new linting rules before continuing:
npm run lint:fix
Commit your changes:
git add .eslintrc.json .eslintignore src/ package.json package-lock.json
git commit -m "build: Configure eslint"
Update your VSCode workspace settings with:
{
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.formatOnSave": true,
"eslint.alwaysShowStatus": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
}
Or copy/paste this custom settings.json
file in .vscode/
.
Install Vitest and React Testing Library packages:
npm install vitest jsdom @vitest/ui @testing-library/react @testing-library/jest-dom @testing-library/user-event --save-dev
Add a setup.ts
file at src/test/
:
import "@testing-library/jest-dom";
Update vite.config.ts
:
/// <reference types="vitest" />
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: "jsdom",
setupFiles: "./src/test/setup.ts"
}
})
Update your package.json
file with test
scripts:
"scripts": {
"test": "vitest run",
"test:ui": "vitest --ui",
"test:watch": "vitest"
}
Create a App.test.tsx
test file along App.tsx
file:
import { render, screen } from "@testing-library/react";
import user from "@testing-library/user-event";
import App from "./App";
describe("App", () => {
describe("when button is clicked", () => {
it("should increment the counter", async () => {
render(<App />);
user.click(screen.getByRole("button"));
expect(await screen.findByText(/count is 1/i)).toBeInTheDocument();
});
});
});
Commit your changes:
git add src/ vite.config.ts package.json package-lock.json
git commit -m "build: Configure vitest"
Use husky-init
to set up husky:
npx husky-init && npm install
Update the default pre-commit
hook to run ESLint:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint
npm run test
Install commitlint
with Angular config:
npm install @commitlint/{cli,config-angular} --save-dev
Create a .commitlintrc.json
file at the root of your project and configure commitlint
to use Angular config:
{
"extends": ["@commitlint/config-angular"]
}
Or, if you like Angular configuration but prefer using sentence-case
(first letter uppercase) for the subject, you can copy/paste this .commitlintrc.json
config file at the root of your project. In this guide, I'm using this opinionated configuration.
Create a commit-msg
hook:
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
Commit your changes:
git add .husky/ .commitlintrc.json package.json package-lock.json
git commit -m "build: Configure git hooks with husky"
On GitHub main page, go to Settings
-> Developer settings
-> Personal access tokens
-> Tokens (classic)
or directly to https://github.com/settings/tokens.
Generate a new token, name it <project-name>-release-access
and copy it:
- For a public repo, select the
public_repo
scope - For a private repo, select the parent
repo
scope
On your GitHub repository page, go to Settings
-> Secrets
-> Actions
.
Create a new repository secret, name it ACTIONS_RELEASE_ACCESS_TOKEN
and paste the generated token into the Secret
body.
Install semantic-release
package:
npm install semantic-release --save-dev
Create a .releaserc
config file at the root of your project:
branches:
- main
debug: false
ci: true
dryRun: false
plugins:
- "@semantic-release/commit-analyzer"
- "@semantic-release/release-notes-generator"
- "@semantic-release/github"
Create a ci.yml
file in .github/workflows/
.
You can copy/paste this custom ci.yml
file.
git add .github/ .releaserc package.json package-lock.json
git commit -m "ci: Configure actions ci workflow"
Create a free account on Vercel.
Keep the default settings and import your project into Vercel. The repository needs to be public for Vercel to deploy it.
After your project has been imported and deployed, all subsequent pushes to branches will generate preview deployments, and all changes made to the production branch (commonly “main”) will result in a production deployment.
Feel free to create a develop
branch to not push directly into the main
production branch.