前端代碼規(guī)范由約定和約束兩部分,約束部分通過ESLint實現(xiàn),約定部分需要主動遵循。
代碼約束
通過ESLint從兩個方面對代碼進行約束:
- 代碼風(fēng)格:比如使用空格還是使用Tab,每行代碼的最大長度等代碼格式。
- 代碼質(zhì)量:對容易導(dǎo)致bug、可能導(dǎo)致潛在問題的寫法約束,比如不能使用
var、判斷條件不能為常量等。
ESLint
ESLint是用于檢測代碼是否符合用戶定制規(guī)則的工具,通過VSCode ESLint插件實現(xiàn)自動檢測代碼并自動修復(fù)。
- 下載ESLint:
yarn add eslint --dev; - 配置ESLint: 在項目根目錄新建
.eslintrc文件并寫好配置,配置信息示例:
{
env: {
browser: true,
es6: true,
},
rules: {
semi: ["error", "never"],
quotes: ["error", "double"],
},
}
- 安裝ESLint插件;
- 當保存文件時開啟自動修復(fù)功能,打開VSCode設(shè)置,修改設(shè)置:
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
通過上面四步,開發(fā)中有不符合規(guī)范的代碼,VSCode會自動報錯,且有些代碼可以自動修復(fù)。
代碼風(fēng)格Prettier
我們采用Prettier作為代碼風(fēng)格規(guī)范。Prettier是一款代碼格式化工具,它可以解析你的代碼并輸出為符合一定代碼風(fēng)格規(guī)范的代碼。使用它團隊成員無需再討論代碼格式問題了。我們在ESLint中繼承Prettier規(guī)則:
- 安裝依賴:
yarn add prettier --exact --dev,yarn add --dev eslint-config-prettier eslint-plugin-prettier。注意prettier不同版本規(guī)則不同,所以要指定具體版本。 - ESLint配置中繼承規(guī)則,注意prettier配置要放在最后,否則可能引起prettier規(guī)則和其它規(guī)則沖突。配置如下:
{
"extends": ["plugin:prettier/recommended"]
}
通過以上兩步我們就在ESLint中集成了Prettier,保證了代碼風(fēng)格的統(tǒng)一。
代碼質(zhì)量規(guī)范
npm包eslint-config-react-app包含了很多ESLint配置規(guī)則:
- es6相關(guān)的規(guī)則;
- typescript相關(guān)的規(guī)則;
- react相關(guān)的規(guī)則。
我們項目是基于Create React App創(chuàng)建的TypeScript項目,默認包含了該規(guī)則。如果項目不是基于Create React App創(chuàng)建,需要安裝相關(guān)依賴包,并繼承配置。通過繼承eslint-config-react-app我們實現(xiàn)了對代碼質(zhì)量的約束。
pre-commit攔截
通過ESLint和prettier、react-app兩個配置文件,我們實現(xiàn)了代碼規(guī)范的約束。但是如果沒有安裝VSCode插件ESLint,那么約束是失效的,不合乎代碼規(guī)范的代碼有可能進入代碼庫。我們通過 git pre-commit鉤子在代碼提交前執(zhí)行eslint命令,那么不合乎代碼規(guī)范的代碼就會報錯、commit失敗,從而保證入庫的代碼都是合乎代碼規(guī)范的。
husky是觸發(fā)git 鉤子的包,通過它我們可以在配置文件package.json中配置要執(zhí)行的命令。lint-staged是對暫存區(qū)的文件執(zhí)行任意的命令。安裝包: yarn add husky lint-staged --dev,package.json配置:
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx}": [
"eslint --max-warnings 0"
]
}
}
通過上面配置當提交代碼時會觸發(fā)pre-commit命令,然后執(zhí)行lint-staged命令,最后對暫存區(qū)的文件執(zhí)行eslint命令。
代碼約定
代碼約定中主要是關(guān)于開發(fā)中積累的一些最佳實踐、不能使用ESLint的規(guī)則等。
- 異步方案
推薦寫法
async function fn() {
await promise...
}
不推薦寫法
async function fn() {
Promise.then((resolve, reject) => {
...
}).then((resolve, reject) => {
...
});
}
- 使用枚舉
代碼中使用兩次以上的字面量,要定義為枚舉變量
- hoc
class 組件使用裝飾器模式;Function 組件如果有兩層以上 hoc,要使用 compose 組織。
export default compose<React.ComponentClass<IProps, any>>(
create(),
translate()
)(AppListHead);
- 禁用 componentWillReceiveProps, UNSAFE_componentWillReceiveProps()
componentWillReceiveProps 易引發(fā) bug,增加代碼復(fù)雜度,react 17 中將會被移除。以下替代方案使組件可預(yù)測、可維護:
- props 改變時,執(zhí)行副作用(數(shù)據(jù)提取),使用 componentDidUpdate
- props 改變時,重新計算某些數(shù)據(jù),使用 memoize
- props 改變時,重置 state,使組件完全受控或使用 key 使組件完全不受控
- props 傳遞明確
傳遞給組件的 props 不要冗余,只傳遞必要的 props;不可把父組件實例傳遞給子組件。
//不推薦寫法
<SubComponent {...this.props} parent={this}/>
- 避免數(shù)據(jù)突變
直接修改 redux 中的數(shù)據(jù),容易導(dǎo)致不易察覺的 bug。對于復(fù)雜數(shù)據(jù),推薦使用immer。
- 單個 JS 文件不超過 800 行
超過 800 行,要考慮組件拆分。
參考
- eslint https://eslint.org/
- prettier https://prettier.io/
- lint-staged https://github.com/okonet/lint-staged