

pnpm i -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-vue eslint-plugin-react eslint-plugin-import eslint-plugin-simple-import-sort
pnpm i -D prettier eslint-config-prettier eslint-plugin-prettier
pnpm i -D husky lint-staged @commitlint/cli @commitlint/config-conventionalpackage.json 脚本与 lint-staged:
{
"scripts": {
"lint": "eslint --ext .ts,.tsx,.js,.vue src",
"lint:fix": "eslint --ext .ts,.tsx,.js,.vue src --fix",
"format": "prettier --write .",
"test": "vitest run || jest"
},
"lint-staged": {
"src/**/*.{ts,tsx,js,vue}": ["eslint --fix", "prettier --write"],
"src/**/*.{css,scss,md}": ["prettier --write"]
}
}.eslintrc.cjs:
module.exports = {
root: true,
env: { browser: true, es2021: true, node: true },
parser: '@typescript-eslint/parser',
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
plugins: ['@typescript-eslint', 'import', 'simple-import-sort', 'prettier'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:vue/vue3-recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:import/recommended',
'plugin:import/typescript',
'prettier'
],
settings: { react: { version: 'detect' } },
rules: {
'prettier/prettier': ['error'],
'import/order': ['off'],
'simple-import-sort/imports': ['error'],
'simple-import-sort/exports': ['error'],
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'vue/multi-word-component-names': 'off'
},
overrides: [
{ files: ['**/*.vue'], rules: { 'react/jsx-uses-react': 'off', 'react/react-in-jsx-scope': 'off' } },
{ files: ['**/*.tsx'], rules: { 'vue/no-unused-components': 'off' } }
]
}.prettierrc.json:
{ "semi": false, "singleQuote": true, "printWidth": 100, "trailingComma": "es5" }可选 .editorconfig:
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
end_of_line = lf
insert_final_newline = true初始化与钩子:
npx husky init.husky/pre-commit:
npx lint-staged.husky/commit-msg:
npx commitlint --edit "$1".husky/pre-push:
pnpm testcommitlint.config.cjs:
module.exports = { extends: ['@commitlint/config-conventional'] }提交信息示例:
feat(auth): 支持短信验证码登录
fix(router): 修复刷新后白屏问题
chore(deps): 升级 eslint 到最新版本lint-staged 可在根目录配置并针对各包的 src/ 路径匹配lint/test).github/workflows/quality.yml:
name: Quality
on: { pull_request: { branches: [main] }, push: { branches: [main] } }
jobs:
lint_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'pnpm' }
- run: corepack enable
- run: pnpm i --frozen-lockfile
- run: pnpm lint
- run: pnpm test -- --coveragesimple-import-sort 以组为单位排序,避免冲突plugin:vue/vue3-recommended;React 项目开启 react-hooks 规则.eslintignore 与 .prettierignore.eslintignore 与 .prettierignore:
dist
node_modules
coverage
*.min.jsextends 中最后是 prettier,开启 prettier/prettier 错误级别.husky 目录在仓库根且钩子文件可执行;在 CI 环境只执行脚本不启用钩子overrides 针对 .vue 与 .tsx 设置规则差异{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": { "source.fixAll.eslint": true },
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue" ]
}feat 映射 minor、fix 映射 patch、含 BREAKING CHANGE 映射 major。
Changesets 或 semantic-release 可自动生成版本与变更日志。
{
"lint-staged": {
"src/**/*.{ts,tsx,js,vue}": ["eslint --fix --cache", "prettier --write"],
"*.{css,scss,md}": ["prettier --write"]
}
}{
"coverageThreshold": { "global": { "branches": 70, "functions": 70, "lines": 70 } }
}vue/no-mutating-props、vue/require-prop-typesreact/jsx-no-useless-fragment、react/no-array-index-key、react-hooks/exhaustive-depsstylelint 与 eslint-plugin-jest 或 @testing-library/eslint-plugincommitlint.config.cjs:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', ['feat','fix','chore','docs','refactor','perf','test','build','ci','revert']],
'scope-enum': [2, 'always', ['app','ui','api','deps','lint','release']],
'subject-case': [2, 'never', ['sentence-case','start-case','pascal-case','upper-case']],
'header-max-length': [2, 'always', 72]
}
}.eslintrc.cjs 片段:
rules: {
'simple-import-sort/imports': ['error', {
groups: [
['^react', '^vue', '^@?\w'],
['^(@/)(.*)$'],
['^\.\.(?!/?$)', '^\.'],
['^.+\.s?css$']
]
}]
}.gitattributes:
* text=auto eol=lf统一跨平台换行(LF),避免格式化差异。
在钩子中开启 ESLint 缓存、控制并发与匹配范围:
{
"lint-staged": {
"src/**/*.{ts,tsx,js,vue}": ["eslint --fix --cache", "prettier --write"],
"*.{css,scss,md}": ["prettier --write"]
}
}pre-commit/commit-msg/pre-pushlint 与 test 并采集覆盖率