React+Typescript+Webpack5+Eslint+Prettier project setup
Initialize the project
Create the project with npx create-react-app eslint_demo --template typescript.
Install the related eslint and prettier dependencies: npm i -D eslint eslint-plugin-prettier eslint-config-prettier prettier.
Next, you can add the .vscode settings so the IDE auto-formats:
// in the .vscode/settings.json
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.alwaysShowStatus": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"editor.formatOnSave": true
}
Webpack setup
Install webpack dependencies
npm i -D webpack webpack-cli webpack-dev-server
Install babel-related dependencies
We need babel and the related dependencies to make sure webpack can read .tsx files.
npm i -D babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime @babel/preset-react
The role of each dependency is as follows:
| Dependency | Purpose |
|---|---|
| babel-loader | The transpiler loader; converts .jsx to .js, but its main role is just to recognize .jsx |
| @babel/core | Once babel-loader recognizes .jsx, this dependency does the actual transpilation |
| @babel/preset-env | A preset for babel transpilation, converting things like es6 const/let syntax into lower-version, compatible syntax |
| @babel/plugin-transform-runtime | Transforms higher-version built-in modules; can be seen as a supplement to @babel/preset-env |
| @babel/preset-react | Converts jsx tags into React.createElement |
| @babel/preset-typescrpt | Lets babel support TypeScript syntax |
Configure babel by adding .babelrc to the root
Babel officially recommends adding .babelrc to the project root to configure babel. Combined with the dependencies above, the .babelrc will look like this:
{
"presets": ["@babel/env", "@babel/preset-react", "@babel/preset-typescript"],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"regenerator": true
}
]
]
}
Add the loader in webpack
// webpack.base.js
const path = require('path');
module.exports = {
// entry file
entry: {
main: path.resolve(__dirname, '../src/packages/home/index.tsx'),
},
module: {
rules: [
{
// recognize jsx js tsx ts files at the same time
test: /\.(t|j)sx?$/,
use: 'babel-loader',
},
],
},
};
The setting here sends .js, .ts, .jsx, and .tsx files all to babel-loader for processing.
Configure ESLint
Install the related dependencies
Install the React/TypeScript/ESLint-related dependencies. First, install the eslint airbnb rule set, which will automatically install the related ESLint dependencies:
npx install-peerdeps --dev eslint-config-airbnb
Install the eslint+prettier dependencies:
npm i -D prettier eslint-config-prettier eslint-plugin-prettie
Install the React-test-related dependencies:
npm i -D eslint-plugin-testing-library eslint-plugin-jest-dom
In addition to the basic eslint+prettier dependencies, this also covers React, react-test, jest-dom, etc., making it easy for React engineers to write code and tests.
Configure .eslintrc.js
Add .eslintrc.js at the project root, and declare the ESLint rule sets you want to use under extends:
extends: [
'airbnb',
'plugin:jsx-a11y/recommended',
'plugin:testing-library/react',
'plugin:jest-dom/recommended',
'eslint:recommended',
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
],
Then update parser and parserOptions so ESLint can read .ts and .tsx:
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: './tsconfig.json',
},
At this point, however, .eslintrc.js itself will report an error: Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.. And if there are also webpack-related files in the project (like webpack.config.js), they will produce similar errors. The reason is that we are using @typescript-eslint/parser to parse all files. The simplest fix is to have ESLint skip those files directly:
- Add
.eslintrcIgnoreat the root Inside it, list the files you want to exclude from type-checking
.eslintrc.js webpack.common.js webpack.local.js
With that, the basic setup is done. The remaining rules can be written based on team consensus.
Full .eslintrc.js:
module.exports = {
env: {
browser: true,
es2021: true,
jest: true,
node: true,
},
extends: [
'airbnb',
'plugin:jsx-a11y/recommended',
'plugin:testing-library/react',
'plugin:jest-dom/recommended',
'eslint:recommended',
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: './tsconfig.json',
},
plugins: [
'react',
'@typescript-eslint',
'react-hooks',
'jsx-a11y',
'simple-import-sort',
'jest-dom',
'testing-library',
'prettier',
],
rules: {
'import/no-extraneous-dependencies': [2, { devDependencies: true }],
'testing-library/await-async-query': 'error',
'testing-library/no-await-sync-query': 'error',
'testing-library/no-debugging-utils': 'warn',
'jest-dom/prefer-checked': 'error',
'jest-dom/prefer-enabled-disabled': 'error',
'jest-dom/prefer-required': 'error',
'jest-dom/prefer-to-have-attribute': 'error',
'react/prop-types': ['off'],
'react/jsx-filename-extension': [1, { extensions: ['.tsx', '.jsx'] }],
'import/extensions': [
'error',
'never',
{
scss: 'always',
},
],
'import/prefer-default-export': 0,
'import/no-anonymous-default-export': 0,
'import/no-unresolved': 0,
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
'sort-imports': 'off',
'import/order': 'off',
'no-use-before-define': 'off',
'no-shadow': 'off',
'@typescript-eslint/no-shadow': 'error',
'@typescript-eslint/ban-ts-comment': 0,
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/prefer-optional-chain': 'warn',
'@typescript-eslint/no-inferrable-types': 'warn',
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'react/no-array-index-key': 'off',
'react/react-in-jsx-scope': 'off',
'prettier/prettier': [
'error',
{
endOfLine: 'auto',
},
],
'react/jsx-one-expression-per-line': 'off',
'react/jsx-curly-newline': 'off',
'no-param-reassign': [
'error',
{
props: true,
ignorePropertyModificationsFor: ['state'],
},
],
},
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
paths: ['src'],
},
},
},
}
ChangeLog
- 20220911 - init
- 20260501–translate by claude code