Getting started with creating a frontend project quickly
Tags: typescript, react, webdev, beginners
Published: 2022-11-20 14:38:32

How to create a frontend project from zero quickly? Let's talk about the steps of creating a new project since 2022.


## Preparation
First, the installations of Node.js and package manager are required in your local environment. pnpm is recommanded, and pnpm can also be used directly as Node.js version manager. 

Install pnpm：
```bash
# Mac or Linux
curl -fsSL https://get.pnpm.io/install.sh | sh -

# Windows
iwr https://get.pnpm.io/install.ps1 -useb | iex
```

Install the LTS version of Node.js using pnpm:
```bash
pnpm env use --global lts
```


## Create a project
I will show how to create a project using React and TypeScript as an example.


### Scaffold
For a new project, using vite is highly recommanded. We can create a inital project based on vite by running the command:
```bash
pnpm create vite my-react-app --template react-ts
```

We can see the following directory structure：
```
.
├── public
├── src
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
```

### ESLint
ESint is very useful and necessary with checking errors in your code by static analysis. Here we choose the aribnb style eslint rules which are very popular in the community. Install the corresponding packages via the following command：
```bash
pnpm add eslint eslint-config-airbnb-base eslint-plugin-import -D 
```

And then add a new file named .eslintrc.json in your root directory:
```json
{
  "extends": [
    "eslint:recommended",
    "airbnb-base",
  ],
  "plugins": [
    "import"
  ],
}
```

#### Support TypeScript and React
For a project using typescript and react, additonal parser and plugin are required to support, install them first:
```bash
# TypeScirpt eslint parser
pnpm add @typescript-eslint/parser @typescript-eslint/eslint-plugin -D

# React eslint plugin
pnpm add eslint-plugin-react eslint-plugin-react-hooks -D
```

Then add configurations about it in `.eslintrc.json`:
```json
{
   "extends": [
    "eslint:recommended",
    "airbnb-base",
    "plugin:react/recommended",
    "plugin:react/jsx-runtime",
    "plugin:react-hooks/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "plugins": [
    "import",
    "@typescript-eslint",
    "react",
  ],
  "parser": "@typescript-eslint/parser"
}
```

Finally we add the script in package.json to run eslint:
```json
{
  "scripts": {
     "lint": "eslint --fix --quiet --ext .ts,.tsx src"
  }
}
```

### Prettier
Prettier is a tool for code formatting, it can help us to manage our code style, for instance code indent and blank lines. Install prettier:
```bash
pnpm add prettier -D
```

And then add a new file named .prettierrc.json in your root directory：
```json
{
  "printWidth": 80,
  "tabWidth": 2,
  "semi": true,
  "singleQuote": true
}
```

#### Use prettier with eslint
We can use the ESLint plugin of prettier to check the rules of prettier code style synchronously when checking ESLint rules:
```bash
pnpm add eslint-plugin-prettier eslint-config-prettier -D
```

And then update configurations in .eslintrc.json，Note that you need to set the `prettier/prettier` rules to error：
```json
{
   "extends": [
    "eslint:recommended",
    "airbnb-base",
    "plugin:react/recommended",
    "plugin:react/jsx-runtime",
    "plugin:react-hooks/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ],
  "plugins": [
    "import",
    "@typescript-eslint",
    "react",
    "prettier"
  ],
  "parser": "@typescript-eslint/parser",
  "rules": {
    "prettier/prettier": "error",
  }
}
```

### Husky and lint-staged
After configuring ESLint and prettier, you need a workflow to trigger the related checks. Here we choose the commonly used combination of husky and lint-staged:
```bash
pnpm add husky lint-staged -D
```

Add configurations to package.json in the root directory. It will execute ESLint and prettier fixes when matching files with ts or tsx suffixes:
```json
{
  "lint-staged": {
    "**/*.{ts,tsx}": [
      "eslint --fix --quiet",
      "prettier --write",
      "git add"
    ]
  }
}
```


You are also supposed to add a `precommit` file under `.husky` directory to trigger the behavior of lint-staged:

```bash
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged
```

At last, adding the inital script of husky to package.json to ensure the above hooks can be triggered normally: 
```json
{
  "scripts": {
    "prepare": "husky install"
  }
}
```

If everything works fine. Every time when you commit, husky will trigger the precommit hook first. And then use lint-staged to match file rules. Finally run the related scripts such as eslint and prettier fixes.

### Vitest
Unit testing is a very important part of project development. Through it, the code quality and logical integrity can be guaranteed to a certain extent. For project created with vite, vitest is more compatiable with it to write test cases. Let's install them first:
```bash
pnpm create vitest jsdom -D
```

And then we add configuration jsdom as test environment. After we add the type declaration of vitest at the top, we can configure vitest directly in `vite.config.ts`. The plugins and configurations are shared and there is no need to add a new `vitest.config.ts` file:
```typescript
/// <reference types="vitest" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    testTimeout: 20000,
    environment: 'jsdom',
  },
});
```

A simple example of a test case written using `@testing-library/react` can be found in: [react-typescript](https://github.com/lvqq/cap/blob/main/packages/template-react-typescript/test/dom.test.tsx)

### Github workflow
CI is a important part of project automation. Through CI, we can run some tasks automatically. Take github as an instance, we configurate a workflow, its main function is to run eslint checks, typescript type checks and test cases when you push or pull request your code to github.

At first we need to create `.github/workflows` directory in the root, and then create a file named `ci.yml` under it. Its main content is:
```yaml
name: CI
on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set node v14
        uses: actions/setup-node@v3
        with:
          node-version: '14'
      - name: Install
        run: npm install
      - name: Lint
        run: npm run lint
  typecheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set node v14
        uses: actions/setup-node@v3
        with:
          node-version: '14'
      - name: Install
        run: npm install
      - name: Typecheck
        run: npm run typecheck
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set node v14
        uses: actions/setup-node@v3
        with:
          node-version: '14'
      - name: Install
        run: npm install
      - name: Build
        run: npm run test
```
Here we create three jobs: lint/typecheck/test. They will automatically execute the commands defined in package.json after triggering the push or pull_request operation. By the way, the script typecheck is the same as tsc.

## How to create faster
For current frontend projects, the above typescript, eslint, prettier, husky and etc are basically standard. But it's time-consuming if you re-do such a series of configurations every time you create a new project. So I have developed a personal program that can help you quickly create a project with the above configurations. Only a line of command is needed:
```bash
pnpm create @tooltik/cap my-cap-app --template react-ts
```

The project can be found at: [github](https://github.com/lvqq/cap), any issues, pull requests and suggestions are highly welcomed!