1、安装模块
全局安装 eslint、commitlint 、 check-prettier
npm install eslint commitlint check-prettier -g
本地安装
npm install eslint-config-prettier stylelint stylelint-config-prettier stylelint-config-standard husky @commitlint/config-conventional -D
VSCode 安装 Eslint和Prettier插件
setting.json配置
"eslint.validate": [
"javascript",
"javascriptreact"
],
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"diffEditor.ignoreTrimWhitespace": false,
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.accessibilitySupport": "off",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
2、package 脚本
"scripts": {
"start": "cross-env PORT=3100 REACT_APP_ENV=dev TEAMIND_ENV=dev node scripts/start.js",
"start:https": "cross-env PORT=3100 REACT_APP_ENV=dev HTTPS=https TEAMIND_ENV=dev node scripts/start.js",
"build": "GENERATE_SOURCEMAP=false node scripts/build.js && node scripts/upload.js",
"lint": "npm run lint:fix && npm run lint:prettier && eslint --ext .js,.jsx src",
"lint:fix": "eslint --fix --ext .js,.jsx src && npx stylelint --fix 'src/**/*.less' --syntax less",
"lint:prettier": "check-prettier lint",
"prettier": "node ./scripts/prettier.js",
"prepare": "husky install && npx husky add .husky/pre-commit 'npm run lint \n npm run prettier' && npx husky add .husky/commit-msg 'npx --no-install commitlint --edit `$1`' "
},
3、增加自动化脚本
scripts/getPrettierFiles.js
const glob = require('glob')
const getPrettierFiles = () => {
let files = []
const jsFiles = glob.sync('src/**/*.js*', { ignore: ['**/node_modules/**', 'build/**'] })
const tsFiles = glob.sync('src/**/*.ts*', { ignore: ['**/node_modules/**', 'build/**'] })
const configFiles = glob.sync('config/**/*.js*', { ignore: ['**/node_modules/**', 'build/**'] })
const scriptFiles = glob.sync('scripts/**/*.js')
const lessFiles = glob.sync('src/**/*.less*', { ignore: ['**/node_modules/**', 'build/**'] })
files = files.concat(jsFiles)
files = files.concat(tsFiles)
files = files.concat(configFiles)
files = files.concat(scriptFiles)
files = files.concat(lessFiles)
if (!files.length) {
return
}
return files
}
module.exports = getPrettierFiles
scripts/lint-prettier.js
/**
* copy to https://github.com/facebook/react/blob/master/scripts/prettier/index.js
* prettier api doc https://prettier.io/docs/en/api.html
*----------*****--------------
* lint file is prettier
*----------*****--------------
*/
const prettier = require('prettier')
const fs = require('fs')
const chalk = require('chalk')
const prettierConfigPath = require.resolve('../.prettierrc')
const files = process.argv.slice(2)
let didError = false
files.forEach(file => {
Promise.all([
prettier.resolveConfig(file, {
config: prettierConfigPath,
}),
prettier.getFileInfo(file),
])
.then(resolves => {
const [options, fileInfo] = resolves
if (fileInfo.ignored) {
return
}
const input = fs.readFileSync(file, 'utf8')
const withParserOptions = {
...options,
parser: fileInfo.inferredParser,
}
const output = prettier.format(input, withParserOptions)
if (output !== input) {
fs.writeFileSync(file, output, 'utf8')
// console.log(chalk.green(`${file} is prettier`));
}
})
.catch(e => {
didError = true
})
.finally(() => {
if (didError) {
process.exit(1)
}
console.log(chalk.hex('#1890FF')('prettier success!'))
})
})
scripts/prettier.js
/**
* copy to https://github.com/facebook/react/blob/master/scripts/prettier/index.js
* prettier api doc https://prettier.io/docs/en/api.html
*----------*****--------------
* prettier all js and all ts.
*----------*****--------------
*/
const prettier = require('prettier')
const fs = require('fs')
const getPrettierFiles = require('./getPrettierFiles')
const prettierConfigPath = require.resolve('../.prettierrc')
const chalk = require('chalk')
let didError = false
const files = getPrettierFiles()
files.forEach(file => {
const options = prettier.resolveConfig.sync(file, {
config: prettierConfigPath,
})
const fileInfo = prettier.getFileInfo.sync(file)
if (fileInfo.ignored) {
return
}
try {
const input = fs.readFileSync(file, 'utf8')
const withParserOptions = {
...options,
parser: fileInfo.inferredParser,
}
const output = prettier.format(input, withParserOptions)
if (output !== input) {
fs.writeFileSync(file, output, 'utf8')
console.log(chalk.green(`${file} is prettier`))
}
} catch (e) {
didError = true
}
})
if (didError) {
process.exit(1)
}
console.log(chalk.hex('#1890FF')('prettier success!'))
4、配置文件
.prettierrc
{
"printWidth": 120,
"semi": false,
"trailingComma": "es5",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"singleQuote": true,
"jsxSingleQuote":false,
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}
commitlint.config.js
module.exports = {
extends: [
'@commitlint/config-conventional'
],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'refactor', 'docs', 'chore', 'style', 'revert'
]],
'type-case': [0],
'type-empty': [0],
'scope-empty': [0],
'scope-case': [0],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
'header-max-length': [0, 'always', 72]
}
}
.eslintrc
{
"parser": "babel-eslint",
"extends": ["react-app", "prettier"],
"plugins": [
// ...
"react-hooks"
],
"env": {
"browser": true,
"node": true,
"es6": true,
"mocha": true,
"jest": true,
"jasmine": true
},
"rules": {
// ...
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "error",
"quotes": ["error", "single", { "allowTemplateLiterals": true }],
"semi": ["error", "never"],
"eqeqeq": "off",
"no-use-before-define": "off",
"no-unused-vars": "off",
"array-callback-return": "off",
"no-throw-literal": "off"
}
}
.stylelintrc.json
{
"extends": ["stylelint-config-standard", "stylelint-config-prettier"],
"rules": {
"no-descending-specificity": null,
"no-empty-source": null,
"no-duplicate-selectors": null,
"font-family-no-missing-generic-family-keyword": null,
"selector-pseudo-class-no-unknown": null
}
}
5、安装husky
npm i husky -D 初始化 npm run prepare
# Activate hooks
npx husky install
# or
yarn husky install
# Add hook
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
npx husky add .husky/pre-commit 'npm run prettier npm run lint'
6、 使用
配置后 先执行 npm run prepare 初始化 husky 然后按照规范提交代码即可自动执行全局格式化
7、 问题与解决
通过使用发现的问题与解决方案 问题
- prettier为全局美化代码, 多个文件的提交时, 全局格式化后,会有部分文件美化后,没有提交上去, 需要二次提交, 或者git commit --ament --no-edit
- Eslint 检查也为全局检查, 会影响提交速度 解决方案: 安装 "lint-staged" 配置package.json
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint",
"npm run prettier",
"git add"
],
"*.{less,scss}": "npx stylelint --fix src/**/*.less --syntax less"
}
修改.husky
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# npm run lint
# npm run prettier
npx lint-staged
8、参考链接
husky: Husky - Git hooks
使用husky规范commit记录: cloud.tencent.com/developer/a…