Why
團(tuán)隊(duì)開發(fā)中,每個(gè)人的編碼習(xí)慣不同,代碼格式不同。這就會(huì)導(dǎo)致代碼難看,難以維護(hù)。統(tǒng)一代碼風(fēng)格可以:
- 增強(qiáng)代碼的可讀性,降低維護(hù)成本
- 有利于代碼審查
- 養(yǎng)成規(guī)范代碼的習(xí)慣,有利于自身成長(zhǎng)
How
推薦使用 eslint + prettier 來進(jìn)行代碼格式化。
通過 git hook 調(diào)用來實(shí)現(xiàn)代碼的自動(dòng)格式化,git hooks 工具推薦 husky。
既然用到了 git hook,順便把提交信息規(guī)范也做一下,這里推薦 commitlint。
用到的插件
-
eslint: js/jsx 語法檢查插件
按照已有配置檢查 js/jsx 語法,能拋出錯(cuò)誤、警告,并且能修復(fù)一部分錯(cuò)誤 -
stylelint: css樣式格式化工具 -
prettier: 代碼格式化插件
按照已有配置進(jìn)行代碼格式化 -
husky: git hooks 工具
對(duì) git 執(zhí)行的一些命令,通過對(duì)應(yīng)的 hooks 觸發(fā),執(zhí)行自定義的腳本程序。
比如,我們可以定義pre-commit鉤子的腳本為npm run test。這樣在代碼提交前就會(huì)執(zhí)行npm run test -
lint-staged: 在 git 暫存區(qū)運(yùn)行 linters 的工具
只檢查暫存區(qū)內(nèi)容,避免每次 lint 執(zhí)行都針對(duì)所有代碼
相當(dāng)于每次只對(duì)修改的內(nèi)容執(zhí)行 eslint + prettier 格式化 -
commitlint: 提交信息檢查工具
檢查提交信息是否符合規(guī)范
eslint 7.x
1. 安裝
cnpm install eslint -D
2. 使用
- 配置 eslint
eslint --init添加 eslint 配置文件。然后修改配置,具體配置如下:
module.exports = {
// 特定項(xiàng)目下,不再檢索上級(jí)目錄
root: true,
env: {
browser: true,
es6: true,
node: true,
amd: true
},
extends: [
'eslint:recommended',
'plugin:react/recommended',
// eslint-config-prettier的縮寫
'prettier'
],
plugins: ['react'],
// 解析器選項(xiàng)
parserOptions: {
sourceType: 'module',
ecmaFeatures: {
jsx: true
}
},
settings: {
react: {
version: 'detect'
}
},
rules: {
'no-unused-expressions': 'off',
'no-unused-vars': 'warn',
'no-debugger': 'error',
'no-unreachable': 'warn',
'react/prop-types': 'off'
}
};
這里,我們用到了幾個(gè) eslint 的插件,需要安裝:
cnpm install eslint-config-prettier eslint-plugin-react -D
eslint-config-prettier 的作用是使用 Prettier 默認(rèn)推薦配置,并且關(guān)閉 eslint 自身的格式化功能,防止 Prettier 和 ESLint 的自動(dòng)格式化的沖突
在 package.json 的 scripts 里添加 eslint 腳本命令,如下:
"scripts": {
// ...
"eslint": "eslint --ext js,jsx src --fix",
},
值得注意的是,這里我們指定了 src 目錄,所以沒必要再加.eslintignore文件了。
npm run eslint即可進(jìn)行 eslint 檢查和修復(fù)(只能修復(fù)部分格式的問題)。
stylelint14.x
1. 安裝
cnpm install stylelint -D
2. 配置
創(chuàng)建.stylelintrc.js,增加以下配置:
module.exports = {
extends: ["stylelint-config-standard-scss", "stylelint-config-prettier"],
plugins: ["stylelint-order"],
defaultSeverity: "warning",
overrides: [],
rules: {
"color-no-invalid-hex": true,
"annotation-no-unknown": true,
"function-calc-no-unspaced-operator": true,
"function-no-unknown": true,
"block-no-empty": true,
"unit-allowed-list": ["em", "rem", "s", "%", "px", "vw", "vh"],
"no-duplicate-selectors": true,
"selector-class-pattern": null,
"order/properties-order": [
"position",
"top",
"right",
"bottom",
"left",
"z-index",
"display",
"justify-content",
"align-items",
"float",
"clear",
"overflow",
"overflow-x",
"overflow-y",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"border",
"border-style",
"border-width",
"border-color",
"border-top",
"border-top-style",
"border-top-width",
"border-top-color",
"border-right",
"border-right-style",
"border-right-width",
"border-right-color",
"border-bottom",
"border-bottom-style",
"border-bottom-width",
"border-bottom-color",
"border-left",
"border-left-style",
"border-left-width",
"border-left-color",
"border-radius",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left",
"width",
"min-width",
"max-width",
"height",
"min-height",
"max-height",
"font-size",
"font-family",
"font-weight",
"text-align",
"text-justify",
"text-indent",
"text-overflow",
"text-decoration",
"white-space",
"color",
"background",
"background-position",
"background-repeat",
"background-size",
"background-color",
"background-clip",
"opacity",
"filter",
"list-style",
"outline",
"visibility",
"box-shadow",
"text-shadow",
"resize",
"transition"
]
}
};
這里, 我們用到了幾個(gè)插件:
stylelint-config-standard-scss: stylelint默認(rèn)規(guī)則只能格式化css,這里我們使用該插件的規(guī)則來格式化scss。
stylelint-config-prettier: 避免stylelint與prettier沖突的插件。
stylelint-order: 給屬性排序的插件。屬性會(huì)按照rules里 order/properties-order 所定義的順序排序。
此外,我們還要安裝stylelint-scss,因?yàn)閟tylelint默認(rèn)是沒有格式化scss的能力的。
安裝:
cnpm install stylelint-scss stylelint-config-standard-scss stylelint-config-prettier stylelint-order -D
在 package.json 的 scripts 里添加 stylelint 腳本命令,如下:
"scripts": {
// ...
"stylelint": "stylelint src/**/*.{less,scss,css} --fix",
},
使用npm run stylelint即可對(duì)src下的樣式文件進(jìn)行格式化。
prettier
1. 安裝
cnpm install prettier -D
2. 使用
- 配置 prettier
創(chuàng)建 prettierrc.js 文件:
echo module.exports = {}>.prettierrc.js
添加配置,這里可以根據(jù)自己需要調(diào)整風(fēng)格。比如:
module.exports = {
printWidth: 120,
tabWidth: 2,
useTabs: false,
semi: true,
singleQuote: false,
jsxSingleQuote: true,
jsxBracketSameLine: true,
trailingComma: "none",
bracketSpacing: true
};
最好再加上.prettierignore文件,避免把不必要的文件也進(jìn)行格式化。
#ignore
node_modules
.DS_Store
yarn*
*-lock*
dist*
public/
prettier --write即可進(jìn)行 prettier 格式化。
lint-stated 13.x
1. 安裝
cnpm install lint-staged -D
2. 使用
- 在 package.json 里添加 lint-staged 選項(xiàng)
"lint-staged": {
"**/*.{js,jsx,ts,tsx}": [
"eslint --fix"
],
"**/*.{js,jsx,ts,tsx,cjs,json,less,scss,css,md}": [
"prettier --write"
],
"**/*.{less,scss,css}": [
"stylelint --fix"
]
},
- 在 package.json 的 scripts 里添加 lint-staged 腳本命令
"scripts": {
// ...
"lint-staged": "lint-staged"
},
這樣,當(dāng)我們使用npm run lint-staged的時(shí)候,就會(huì)自動(dòng)調(diào)用 eslint+prettier 格式化。
commitlint
1. 安裝
cnpm install --save-dev @commitlint/config-conventional @commitlint/cli
2. 使用
- 初始化 commitlint 配置文件
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
- 配置 commitlint
- 提交信息結(jié)構(gòu)
通常 commitlint 認(rèn)為我們提交信息格式如下:
- 提交信息結(jié)構(gòu)
type(scope?): subject
body?
footer?
其中, scope/body/footer 這三個(gè)可有可無。
- 校驗(yàn)規(guī)則
一般的校驗(yàn)規(guī)則格式如下:
[規(guī)則名稱]: [level, when, value]
level: 有三個(gè)參數(shù)。0 代表禁用, 1 代表警告, 2 代表錯(cuò)誤
when: 有兩個(gè)參數(shù)。always 代表總是, never 代表從不
value: 參數(shù)值
比如:
"subject-empty": [2, "never"],
"body-empty": [2, "always"],
"type-enum": [2, "always", ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'revert']]
就是強(qiáng)制 body 必須為空,subject 不可為空,type 必須是上面數(shù)組里的其中一個(gè)。不然就報(bào)錯(cuò)。
git commit -m "feat: 增加了新功能"
git commit -m "fea: 增加了新功能" // 報(bào)錯(cuò),type 必須為'feat', 'fix', 'docs', 'style', 'refactor', 'test', 'revert'中的一個(gè)
更多規(guī)則參考官網(wǎng)
https://commitlint.js.org/#/reference-rules
- 自定義校驗(yàn)規(guī)則
如果已有的規(guī)則滿足不了需求,我們還可以自定義校驗(yàn)規(guī)則。自定義校驗(yàn)規(guī)則寫在 plugins 屬性中。
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
"type-empty": [2, "always"],
"scope-empty": [2, "always"],
"subject-empty": [2, "always"],
"header-max-length": [2, "always", 100],
"body-empty": [2, "always"],
"footer-empty": [2, "always"],
"action-enum": [
2,
"always",
["Fixed", "Feature", "Add", "Modify", "Update", "Delete"]
],
"issue-rule": [2, "always", ["TMP", "TTT"]] // 根據(jù)自己需要輸入即可
},
plugins: [
{
rules: {
"action-enum": ({ raw }, when = "always", value = []) => {
return [
value.includes(raw.split(" ")[0]),
`提交信息不合規(guī)范! {Action}錯(cuò)誤!
必須以 "{Action}{空格}#{標(biāo)號(hào)}{空格}" 開頭。
{Action}可選:${value.join("|")}
比如: Fixed #TMP-111 修復(fù)接口傳參錯(cuò)誤的問題
${when === "never" ? "另外: action-enum規(guī)則第二個(gè)參數(shù)必須是always, 建議修改" : ""}...`
];
},
"issue-rule": ({ raw }, when, value = []) => {
const issueStr = `^([A-Z][a-z]*\\s#(${value.join("|")})\\-[1-9][0-9]*)`;
const issueReg = new RegExp(issueStr, "g");
return [
issueReg.test(raw),
`提交信息不合規(guī)范! {標(biāo)號(hào)}錯(cuò)誤!
必須以 "{Action}{空格}#{標(biāo)號(hào)}{空格}" 開頭。
{標(biāo)號(hào)}可選: ${value.join("|")}
比如: Fixed #TMP-111 修復(fù)接口傳參錯(cuò)誤的問題
${when === "never" ? "另外: action-enum規(guī)則第二個(gè)參數(shù)必須是always, 建議修改" : ""}...`
];
}
}
}
]
};
這里,我把 type, scope, subject, body, footer 都強(qiáng)制為空,然后自定義了兩個(gè)規(guī)則action-enum和issue-rule。
提交代碼的時(shí)候,如果不符合'必須以 "{Action}{空格}#{標(biāo)號(hào)}{空格}" 開頭'的規(guī)則,就會(huì)報(bào)錯(cuò),提交失敗。例如:
git commit -m "Fixed #TMO-222 修復(fù)了傳參錯(cuò)誤的bug"
由于我們定義的標(biāo)號(hào)前綴里面沒有TMO,因此會(huì)報(bào)錯(cuò):

husky 8.x
1. 安裝
cnpm install husky -D
2. 使用
npm set-script prepare "husky install"
npm run prepare
這里我們?cè)?scripts 加了一個(gè) prepare 命令,這個(gè)命令會(huì)在執(zhí)行 npm install 時(shí)自動(dòng)執(zhí)行。
npx husky add .husky/pre-commit "npm run lint-staged"
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
這里我們添加了兩個(gè)鉤子,pre-commit 與 commit-msg。
pre-commit 會(huì)在提交前執(zhí)行npm run lint-staged命令
commit-msg 會(huì)在提交時(shí)執(zhí)行npx --no-install commitlint --edit "$1"
至此,我們的配置完成。代碼提交的時(shí)候會(huì)自動(dòng)對(duì)修改的代碼進(jìn)行格式化,同時(shí)會(huì)按照 commitlint 里的設(shè)置來進(jìn)行提交信息校驗(yàn)。
如果有問題,則會(huì)報(bào)錯(cuò),且代碼會(huì)提交失敗。
vscode 插件
1. eslint 和 prettier 插件
推薦使用 vscode 插件 eslint 和 prettier,可以在 settings.json 中設(shè)置:
"editor.formatOnSave": true,
"eslint.run": "onSave"
當(dāng)我們保存的時(shí)候,會(huì)自動(dòng)進(jìn)行格式化, 會(huì)自動(dòng)把 eslint 的錯(cuò)誤語法用波浪線標(biāo)出來。
2. 把 eslint 和 prettier 插件配置加到項(xiàng)目目錄
vscode 的配置分兩類,工作區(qū)和用戶區(qū)。工作區(qū)的優(yōu)先級(jí)高于用戶區(qū)。
在項(xiàng)目根目錄加上.vscode 文件夾,里面是 settings.json 文件。
那么我們的項(xiàng)目就是一個(gè)工作區(qū)了。
修改 settings.json 配置如下:
{
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.formatOnSave": true,
"eslint.run": "onSave"
}
這樣就完成了 vscode 配置的共享。
參考資料:
husky官方文檔
lint-staged官方文檔
commitlint官方網(wǎng)站
commitlint 從0到1 (git commit 校驗(yàn)工具)
前端架構(gòu)師神技,三招統(tǒng)一代碼風(fēng)格(一文講透)