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…