目前在多人项目开发时发现很多代码不规范的地方,因为每个项目都是多人维护,再加上各种历史代码的不同风格,这些情况很容易就造成了代码规范落地难,项目中出现大量低质量代码,代码格式难统一。所以采用 eslint+husky+stylelint+lint-staged+commitlint 这几个工具能够有效解决上述问题。
配置
安装依赖
npm install -D eslint stylelint stylelint-config-standard stylelint-order stylelint-config-css-modules postcss-less husky lint-staged@8 @commitlint/config-conventional @commitlint/cli
1.eslint
定义:ESLint是一个用来识别 ECMAScript 并且按照规则给出报告的代码检测工具,使用它可以避免低级错误和统一代码的风格。如果每次在代码提交之前都进行一次eslint代码检查,就不会因为某个字段未定义为undefined或null这样的错误而导致服务崩溃,可以有效的控制项目代码的质量。
参考官方文档配置好 .eslintrc .eslintignore 文件 https://eslint.bootcss.com/
项目根目录添加.eslintrc 文件,如下:
{
"root": true,
"extends": [
"eslint:recommended"
],
"env": {
"node": true,
"es6": true,
"browser": true
},
"parserOptions": {
"parser": "@babel/eslint-parser",
"ecmaVersion": 2020,
"requireConfigFile": false,
"ecmaFeatures": {
"experimentalDecorators": true,
"experimentalObjectRestSpread": true,
"impliedStrict": true,
"classes": true,
"jsx": true
},
"sourceType": "module"
},
// "plugins": [
// "react"
// ],
"rules": {
//强制统一缩进
"indent": ["error", 4],
// 禁止未使用的变量
"no-unused-vars": 1,
"no-console": [
"error",
{
"allow": [
"log",
"warn",
"error",
"info"
]
}
],
"no-duplicate-case": 2,
// 禁止空语句块
"no-empty": 2,
"no-ex-assign": 2,
"no-extra-boolean-cast": 2,
"no-shadow": 0,
// 禁止 function 定义中出现重名参数
"no-mixed-spaces-and-tabs": [
"error",
"smart-tabs"
],
//使用分号
"semi": [
2,
"always"
],
// 要求操作符周围有空格
"space-infix-ops": 2,
//防止使用未知的DOM属性
// "react/no-unknown-property": 2,
//防止在componentDidUpdate中使用setState
// "react/no-did-update-set-state": 2,
//防止在JSX中重复的props
// "react/jsx-no-duplicate-props": 2,
//在数组或迭代器中验证JSX具有key属性
// "react/jsx-key": 2,
// 强制使用一致的换行风格
"linebreak-style": [
2,
"unix"
],
// 强制在 yield* 表达式中 * 周围使用空格
"yield-star-spacing": 2,
// 要求generator 函数内有 yield
"require-yield": 2,
// 要求使用 let 或 const 而不是 var
"no-var": 1,
// 禁止修改 const 声明的变量
"no-const-assign": 2,
"no-useless-escape": 0
},
"globals": {
"var1": "writable",
"ant": "readonly"
}
}
关于可选链操作符和双问号的配置
首先安装依赖:
npm install --save-dev @babel/plugin-proposal-optional-chaining @babel/plugin-proposal-nullish-coalescing-operator
然后根目录创建.babelrc 文件,如下:
//双问号 ?? 的操作符跟 || 类似,如果给定变量值为 null 或者 undefined,则使用双问号后的默认值,否则使用该变量值。
{
"plugins": [
"@babel/plugin-proposal-nullish-coalescing-operator",//双问号
"@babel/plugin-proposal-optional-chaining" //可选链
]
}
然后就可以在项目中使用啦
2 stylelint
定义:Stylelint是一个强大的,现代的代码检查工具,与ESLint类似,Stylelint能够通过定义一系列的编码风格规则帮助我们避免在样式表中出现错误。目前在开源社区上,关于CSS Lint的解决方案主要包括了csslint、SCSS-Lint和Stylelint等几种。而由于Stylelint在技术架构上基于AST 的方式扩展CSS,除原生CSS 语法,其也支持 SCSS、Less 这类预处理器,并且也有非常多的第三方插件,因此这里选择了Stylelint作为CSS Lint工具。
按官方文档的说法你可以按照以下方法运行stylelint检测样式代码。 --fix 用来自动修复,但不能修复所有的问题。 在根目录下创建.stylelintrc.js文件,文件内写入
// .stylelintrc.js
module.exports = {
processors: [],
plugins: ['stylelint-order'],
extends: [
"stylelint-config-standard",
"stylelint-config-css-modules"
],
rules: {
"selector-class-pattern": [ // 命名规范 -
"^([a-z][a-z0-9]*)(-[a-z0-9]+)*$",
{
"message": "Expected class selector to be kebab-case"
}
],
"string-quotes":"single", // 单引号
"at-rule-empty-line-before": null,
"at-rule-no-unknown":null,
"at-rule-name-case": "lower",// 指定@规则名的大小写
"length-zero-no-unit": true, // 禁止零长度的单位(可自动修复)
"shorthand-property-no-redundant-values": true, // 简写属性
"number-leading-zero": "never", // 小数不带0
"declaration-block-no-duplicate-properties": true, // 禁止声明快重复属性
"no-descending-specificity": true, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器。
"selector-max-id": 0, // 限制一个选择器中 ID 选择器的数量
"max-nesting-depth": 3,
"indentation": [2, { // 指定缩进 warning 提醒
"severity": "warning"
}],
"order/properties-order": [ // 规则顺序
"position",
"top",
"right",
"bottom",
"left",
"z-index",
"display",
"float",
"width",
"height",
'max-width',
'max-height',
'min-width',
'min-height',
'padding',
'padding-top',
'padding-right',
'padding-bottom',
'padding-left',
'margin',
'margin-top',
'margin-right',
'margin-bottom',
'margin-left',
'margin-collapse',
'margin-top-collapse',
'margin-right-collapse',
'margin-bottom-collapse',
'margin-left-collapse',
'overflow',
'overflow-x',
'overflow-y',
'clip',
'clear',
'font',
'font-family',
'font-size',
'font-smoothing',
'osx-font-smoothing',
'font-style',
'font-weight',
"line-height",
'letter-spacing',
'word-spacing',
"color",
"text-align",
'text-decoration',
'text-indent',
'text-overflow',
'text-rendering',
'text-size-adjust',
'text-shadow',
'text-transform',
'word-break',
'word-wrap',
'white-space',
'vertical-align',
'list-style',
'list-style-type',
'list-style-position',
'list-style-image',
'pointer-events',
'cursor',
"background",
"background-color",
"border",
"border-radius",
'content',
'outline',
'outline-offset',
'opacity',
'filter',
'visibility',
'size',
'transform',
],
}
};
3.husky
定义: 是一个为 git 客户端增加 hook 的工具。安装后,它会自动在仓库中的 .git/ 目录下增加相应的钩子;比如 pre-commit 钩子就会在你执行 git commit 的触发。我们可以在 pre-commit 中实现一些比如 lint 检查、单元测试、代码美化等操作。 开始如下配置:
为了在安装后自动启动 Git hooks,package.json 需要添加 prepare 脚本:
{
"scripts": {
"prepare": "npm run start:husky && npm run add:hook && npm run add:commit && npm run add:commitlint",
"start:husky": "husky install",
"add:hook": "npx husky add .husky/pre-commit \"npx lint-staged\"",
"add:commit": "npx husky add .husky/commit-msg 'npx --no-install commitlint --edit \"$1\"'",
"add:commitlint": "echo 'module.exports = {extends: [\"@commitlint/config-conventional\"]};' > .commitlintrc.js"
}
}
这样在在安装后就不用手动启动hooks了(而且还可以手动执行npm run prepare省略后续步骤,一站式创建pre-commit,commit-msg等等hooks,并且创建commitlintrc文件)
否则的话就需要手动一步步创建了,首先启动husky:
npx husky install
然后使用 husky 创建一个pre-commit hook:
npx husky add .husky/pre-commit "npx lint-staged"
脚本如下:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
4.lint-staged
定义:是一个仅仅过滤出 Git 代码暂存区文件(被 git add 的文件)的工具;这个很实用,因为我们如果对整个项目的代码做一个检查,可能耗时很长,如果是老项目,要对之前的代码做一个代码规范检查并修改的话,这可能就麻烦了,可能导致项目改动很大。所以这个 lint-staged,对团队项目和开源项目来说,是一个很好的工具,它是对个人要提交的代码的一个规范和约束。 此时我们已经实现了监听 Git hooks,接下来我们需要在 pre-commit 这个 hook 使用 Lint-staged 对代码进行 prettier 的自动化修复和 ESLint 的检查,如果发现不符合代码规范的文件则直接退出 commit。 并且 Lint-staged 只会对 Git 暂存区(git add 的代码)内的代码进行检查而不是全量代码,且会自动将 prettier 格式化后的代码添加到此次 commit 中。 开始如下配置: 在 package.json 中配置:
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"miniapp/**/*.{js,sjs,ts,tsx}": [
"eslint --fix",
"git add"
],
"*.less": [
"stylelint --fix --custom-syntax postcss-less",
"git add"
]
}
"stylelint --fix" 配置设置最重要,不然不会生效,
若使用了less语法,一定要加上 --custom-syntax postcss-less。
--fix会自动给你修复一些可以修复的问题。
上面的配置是指对 css 进行 stylelint 格式化, js 进行 eslint格式化。
5.commitlint
定义:就是校验你的 commit 信息的,提供多种共享配置 开始如下配置: 添加 commit-msg hook,执行如下脚本。
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
脚本如下:
#!/bin/sh
"$(dirname "$0")/_/husky.sh"
npx --no-install commitlint --edit "$1"
然后生成配置文件 commitlint.config.js,当然也可以是 .commitlintrc.js
echo "module.exports = {extends: ['@commitlint/config-conventional']};" > commitlint.config.js
常用的 type 类别如下:
upd:更新某功能(不是 feat, 不是 fix)
feat:新功能(feature)
fix:修补
bug docs:文档(documentation)
style: 格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改 bug 的代码变动)
test:增加测试
chore:构建过程或辅助工具的变动
例如: git commit -m 'feat(husky): 增加 xxx 功能' git commit -m 'bug(husky): 修复 xxx 功能'
6.配合 vscode 插件配套使用
vscode 安装 eslint 插件 在 setting.json 中配置:
{
"workbench.iconTheme": "vscode-icons",
"[javascript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"explorer.confirmDragAndDrop": false,
"[html]": {
"editor.defaultFormatter": "vscode.html-language-features"
},
"[vue]": {
"editor.defaultFormatter": "octref.vetur"
},
"beautify.config": "",
"eslint.validate": [
"javascript", // 用eslint的规则检测js文件
{
"language": "vue", // 检测vue文件
"autoFix": true // 为vue文件开启保存自动修复的功能
},
{
"language": "react", // 检测react文件
"autoFix": true // 为vue文件开启保存自动修复的功能
},
{
"language": "html",
"autoFix": true
}
],
"eslint.autoFixOnSave": true, // 启用保存时自动修复,默认只支持.js文件
// "editor.formatOnSave": true, // 保存时自动格式化,会导致用不了 ?.
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"prettier.trailingComma": "none", // 尾随逗号, none表示对象最后一个属性值不以逗号结尾(es5则相反)
"prettier.arrowParens": "avoid", // 箭头函数只有一个参数时不使用小括号
// "javascript.format.insertSpaceBeforeFunctionParenthesis": true, // 函数括号间的空格
// "javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true,
// "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": true,
// "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": true,
// "javascript.format.insertSpaceAfterConstructor": true,
// "javascript.updateImportsOnFileMove.enabled": "always",
"javascript.updateImportsOnFileMove.enabled": "never",
"eslint.codeAction.disableRuleComment": {},
"editor.tabSize": 4,
"editor.detectIndentation": false,
"editor.renderControlCharacters": true,
"editor.renderWhitespace": "all",
"window.zoomLevel": 0,
"diffEditor.ignoreTrimWhitespace": false,
"terminal.integrated.rendererType": "dom",
"eslint.codeAction.showDocumentation": {},
// "eslint.migration.2_x": "off",
"beautify.options": {},
"workbench.colorTheme": "One Dark Pro",
"typescript.tsdk": "node_modules\\typescript\\lib",
"npm.enableRunFromFolder": true,
"js/ts.implicitProjectConfig.experimentalDecorators": true,
"explorer.confirmDelete": false,
"eslint.nodePath": "",
"javascript.validate.enable": false,
}