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插件

  1. setting.json配置
  2. "eslint.validate": [
  3. "javascript",
  4. "javascriptreact"
  5. ],
  6. "[html]": {
  7. "editor.defaultFormatter": "esbenp.prettier-vscode"
  8. },
  9. "[javascript]": {
  10. "editor.defaultFormatter": "esbenp.prettier-vscode"
  11. },
  12. "[javascriptreact]": {
  13. "editor.defaultFormatter": "esbenp.prettier-vscode"
  14. },
  15. "diffEditor.ignoreTrimWhitespace": false,
  16. "[typescriptreact]": {
  17. "editor.defaultFormatter": "esbenp.prettier-vscode"
  18. },
  19. "editor.accessibilitySupport": "off",
  20. "editor.codeActionsOnSave": {
  21. "source.fixAll.eslint": true
  22. },

2、package 脚本

  1. "scripts": {
  2. "start": "cross-env PORT=3100 REACT_APP_ENV=dev TEAMIND_ENV=dev node scripts/start.js",
  3. "start:https": "cross-env PORT=3100 REACT_APP_ENV=dev HTTPS=https TEAMIND_ENV=dev node scripts/start.js",
  4. "build": "GENERATE_SOURCEMAP=false node scripts/build.js && node scripts/upload.js",
  5. "lint": "npm run lint:fix && npm run lint:prettier && eslint --ext .js,.jsx src",
  6. "lint:fix": "eslint --fix --ext .js,.jsx src && npx stylelint --fix 'src/**/*.less' --syntax less",
  7. "lint:prettier": "check-prettier lint",
  8. "prettier": "node ./scripts/prettier.js",
  9. "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`' "
  10. },

3、增加自动化脚本

scripts/getPrettierFiles.js

  1. const glob = require('glob')
  2. const getPrettierFiles = () => {
  3. let files = []
  4. const jsFiles = glob.sync('src/**/*.js*', { ignore: ['**/node_modules/**', 'build/**'] })
  5. const tsFiles = glob.sync('src/**/*.ts*', { ignore: ['**/node_modules/**', 'build/**'] })
  6. const configFiles = glob.sync('config/**/*.js*', { ignore: ['**/node_modules/**', 'build/**'] })
  7. const scriptFiles = glob.sync('scripts/**/*.js')
  8. const lessFiles = glob.sync('src/**/*.less*', { ignore: ['**/node_modules/**', 'build/**'] })
  9. files = files.concat(jsFiles)
  10. files = files.concat(tsFiles)
  11. files = files.concat(configFiles)
  12. files = files.concat(scriptFiles)
  13. files = files.concat(lessFiles)
  14. if (!files.length) {
  15. return
  16. }
  17. return files
  18. }
  19. module.exports = getPrettierFiles

scripts/lint-prettier.js

  1. /**
  2. * copy to https://github.com/facebook/react/blob/master/scripts/prettier/index.js
  3. * prettier api doc https://prettier.io/docs/en/api.html
  4. *----------*****--------------
  5. * lint file is prettier
  6. *----------*****--------------
  7. */
  8. const prettier = require('prettier')
  9. const fs = require('fs')
  10. const chalk = require('chalk')
  11. const prettierConfigPath = require.resolve('../.prettierrc')
  12. const files = process.argv.slice(2)
  13. let didError = false
  14. files.forEach(file => {
  15. Promise.all([
  16. prettier.resolveConfig(file, {
  17. config: prettierConfigPath,
  18. }),
  19. prettier.getFileInfo(file),
  20. ])
  21. .then(resolves => {
  22. const [options, fileInfo] = resolves
  23. if (fileInfo.ignored) {
  24. return
  25. }
  26. const input = fs.readFileSync(file, 'utf8')
  27. const withParserOptions = {
  28. ...options,
  29. parser: fileInfo.inferredParser,
  30. }
  31. const output = prettier.format(input, withParserOptions)
  32. if (output !== input) {
  33. fs.writeFileSync(file, output, 'utf8')
  34. // console.log(chalk.green(`${file} is prettier`));
  35. }
  36. })
  37. .catch(e => {
  38. didError = true
  39. })
  40. .finally(() => {
  41. if (didError) {
  42. process.exit(1)
  43. }
  44. console.log(chalk.hex('#1890FF')('prettier success!'))
  45. })
  46. })

scripts/prettier.js

  1. /**
  2. * copy to https://github.com/facebook/react/blob/master/scripts/prettier/index.js
  3. * prettier api doc https://prettier.io/docs/en/api.html
  4. *----------*****--------------
  5. * prettier all js and all ts.
  6. *----------*****--------------
  7. */
  8. const prettier = require('prettier')
  9. const fs = require('fs')
  10. const getPrettierFiles = require('./getPrettierFiles')
  11. const prettierConfigPath = require.resolve('../.prettierrc')
  12. const chalk = require('chalk')
  13. let didError = false
  14. const files = getPrettierFiles()
  15. files.forEach(file => {
  16. const options = prettier.resolveConfig.sync(file, {
  17. config: prettierConfigPath,
  18. })
  19. const fileInfo = prettier.getFileInfo.sync(file)
  20. if (fileInfo.ignored) {
  21. return
  22. }
  23. try {
  24. const input = fs.readFileSync(file, 'utf8')
  25. const withParserOptions = {
  26. ...options,
  27. parser: fileInfo.inferredParser,
  28. }
  29. const output = prettier.format(input, withParserOptions)
  30. if (output !== input) {
  31. fs.writeFileSync(file, output, 'utf8')
  32. console.log(chalk.green(`${file} is prettier`))
  33. }
  34. } catch (e) {
  35. didError = true
  36. }
  37. })
  38. if (didError) {
  39. process.exit(1)
  40. }
  41. console.log(chalk.hex('#1890FF')('prettier success!'))

4、配置文件

.prettierrc

  1. {
  2. "printWidth": 120,
  3. "semi": false,
  4. "trailingComma": "es5",
  5. "bracketSpacing": true,
  6. "jsxBracketSameLine": false,
  7. "singleQuote": true,
  8. "jsxSingleQuote":false,
  9. "overrides": [
  10. {
  11. "files": ".prettierrc",
  12. "options": { "parser": "json" }
  13. }
  14. ]
  15. }

commitlint.config.js

  1. module.exports = {
  2. extends: [
  3. '@commitlint/config-conventional'
  4. ],
  5. rules: {
  6. 'type-enum': [2, 'always', [
  7. 'feat', 'fix', 'refactor', 'docs', 'chore', 'style', 'revert'
  8. ]],
  9. 'type-case': [0],
  10. 'type-empty': [0],
  11. 'scope-empty': [0],
  12. 'scope-case': [0],
  13. 'subject-full-stop': [0, 'never'],
  14. 'subject-case': [0, 'never'],
  15. 'header-max-length': [0, 'always', 72]
  16. }
  17. }

.eslintrc

  1. {
  2. "parser": "babel-eslint",
  3. "extends": ["react-app", "prettier"],
  4. "plugins": [
  5. // ...
  6. "react-hooks"
  7. ],
  8. "env": {
  9. "browser": true,
  10. "node": true,
  11. "es6": true,
  12. "mocha": true,
  13. "jest": true,
  14. "jasmine": true
  15. },
  16. "rules": {
  17. // ...
  18. "react-hooks/rules-of-hooks": "error",
  19. "react-hooks/exhaustive-deps": "error",
  20. "quotes": ["error", "single", { "allowTemplateLiterals": true }],
  21. "semi": ["error", "never"],
  22. "eqeqeq": "off",
  23. "no-use-before-define": "off",
  24. "no-unused-vars": "off",
  25. "array-callback-return": "off",
  26. "no-throw-literal": "off"
  27. }
  28. }

.stylelintrc.json

  1. {
  2. "extends": ["stylelint-config-standard", "stylelint-config-prettier"],
  3. "rules": {
  4. "no-descending-specificity": null,
  5. "no-empty-source": null,
  6. "no-duplicate-selectors": null,
  7. "font-family-no-missing-generic-family-keyword": null,
  8. "selector-pseudo-class-no-unknown": null
  9. }
  10. }

5、安装husky

npm i husky -D
初始化 npm run prepare

  1. # Activate hooks
  2. npx husky install
  3. # or
  4. yarn husky install
  5. # Add hook
  6. npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
  7. npx husky add .husky/pre-commit 'npm run prettier npm run lint'

6、 使用

配置后
先执行 npm run prepare 初始化 husky
然后按照规范提交代码即可自动执行全局格式化

7、参考链接

husky: Husky - Git hooks
使用husky规范commit记录: https://cloud.tencent.com/developer/article/1573495