React+Typescript+Webpack5+Eslint+Prettier專案設置
初始化專案
透過 npx create-react-app eslint_demo --template typescript
創建專案
安裝相關的eslint
、prettier
依賴:npm i -D eslint eslint-plugin-prettier eslint-config-prettier prettier
接著,可以直接寫.vscode的設置,讓IDE自動format:
// 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設置
下載webpack dependency
npm i -D webpack webpack-cli webpack-dev-server
下載相關babel
這裏我們需要babel
和相關的dependency來確保webpack能夠讀.tsx
檔案
npm i -D babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime @babel/preset-react
各個依賴的作用如下:
依賴 | 作用 |
---|---|
babel-loader | 轉譯器,將.jsx 轉換為.js ,但主要作用只是識別出.jsx |
@babel/core | babel-loader識別出.jsx ,然後透過此dependancy來轉譯 |
@babel/preset-env | babel轉譯中的一些預設設定,將一些如es6 const/let 語法轉譯成低級並可兼容的語法 |
@babel/plugin-transform-runtime | 轉化高版本內置模塊,可以看作對@babel/preset-env 的補充 |
@babel/preset-react | 將jsx 標籤轉換為React.createElement |
@babel/preset-typescrpt | 讓babel支持Typescript語法 |
配置babel,根目錄新增.babelrc
babel官方推薦,在根目錄下新增.babelrc
來配置babel,配合上述的dependency,在.babelrc
會像這樣:
{
"presets": ["@babel/env", "@babel/preset-react", "@babel/preset-typescript"],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"regenerator": true
}
]
]
}
在webpack中添加loader
// webpack.base.js
const path = require('path');
module.exports = {
// 入口文件
entry: {
main: path.resolve(__dirname, '../src/packages/home/index.tsx'),
},
module: {
rules: [
{
// 同時識別 jsx js tsx ts 文件
test: /\.(t|j)sx?$/,
use: 'babel-loader',
},
],
},
};
這裏的設置是將.js
、.ts
、.jsx
、.tsx
都丟到 babel-loader
做處理。
設置eslint
下載相關dependency
下載react/typescript/eslint相關依賴。首先,安裝 eslint airbnb的規則,其會自動下載相關的eslint dependency
npx install-peerdeps --dev eslint-config-airbnb
下載 eslint+prettier的dependency:
npm i -D prettier eslint-config-prettier eslint-plugin-prettie
下載react test 相關的dependency:
npm i -D eslint-plugin-testing-library eslint-plugin-jest-dom
其中除了基本eslint+prettier的dependency,還有react、react-test、jest-dom等等的eslint dependency,可以讓react工程師很方便的寫代碼和寫測試。
設置.eslintrc.js
在根目錄上新增.eslintrc.js
,現在extends
中先宣告要使用的eslint規則:
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
和parserOptions
,讓eslint可以讀取.ts
和.tsx
。
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: './tsconfig.json',
},
不過此時會看到,.eslintrc.js
本身會報一個錯: Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
,而且如果專案裡還有設置webpack(like: webpack.config.is),也會有相似的報錯。原因就是我們使用@typescript-eslint/parser
對所有檔案做解析,產生的報錯;最簡單的解決辦法,就是讓eslint直接略過相關的檔案:
- 在根目錄上新增
.eslintrcIgnore
在檔案內寫入想要忽略類型檢查的檔案
.eslintrc.js webpack.common.js webpack.local.js
這樣一來基本的設置就完成了,接下來的一些Rules可以基於團隊的共識來撰寫。
完整.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-完成初稿