中小型前端團(tuán)隊(duì)代碼規(guī)范工程化最佳實(shí)踐 - ESLint
作者:axuebing
來(lái)源:Segmentfault 思否社區(qū)
前言
There are a thousand Hamlets in a thousand people's eyes.
單引號(hào)還是雙引號(hào)? 代碼行結(jié)束是否需要分號(hào)? 兩個(gè)空格還是四個(gè)空格? ...
關(guān)于 ESLint
Find Problems。ESLint 通過(guò)靜態(tài)代碼分析可以快速發(fā)現(xiàn)代碼中的問(wèn)題。ESLint 可以運(yùn)行在大多數(shù)文本編輯器中,并且也可以在工作流中接入 ESLint Fix Automatically。ESLint 發(fā)現(xiàn)的很多問(wèn)題都可以自動(dòng)修復(fù) Customize。可以定制 ESLint 檢查規(guī)則
基于業(yè)界現(xiàn)有的 ESLint 規(guī)范和團(tuán)隊(duì)代碼習(xí)慣定制一套統(tǒng)一的 ESLint 代碼規(guī)則 將統(tǒng)一代碼規(guī)則封裝成 ESLint 規(guī)則包接入 將 ESLint 接入腳手架、編輯器以及研發(fā)工作流中
快速上手
package.json 的目錄(可以在空目錄下執(zhí)行 npm init -y),新建一個(gè) index.js:// index.js
const name = 'axuebin'
eslint :npm install eslint --save-dev
./node_modules/.bin/eslint --init 或者 npx eslint --init 生成一個(gè) ESLint 配置文件 .eslintc.js:module.exports = {
env: {
es2021: true,
},
extends: 'eslint:recommended',
parserOptions: {
ecmaVersion: 12,
},
rules: {},
};
./node_modules/.bin/eslint index.js 或者 npx eslint index.js 命令對(duì)文件進(jìn)行檢查。結(jié)果如下
index.js 中的代碼命中了 no-unused-vars 這個(gè)規(guī)則,默認(rèn)情況下,這個(gè)規(guī)則是會(huì)報(bào) error 的,也就是 ESLint 不允許代碼中出現(xiàn)未被使用的變量。這是一個(gè)好習(xí)慣,有利于代碼的維護(hù)。簡(jiǎn)單配置
.eslintrc.js 配置文件,在 rules 中添加相關(guān)配置項(xiàng):module.exports = {
env: {
es2021: true,
},
extends: 'eslint:recommended',
parserOptions: {
ecmaVersion: 12,
},
rules: {
semi: ['error', 'always'],
quotes: ['error', 'single'],
},
};
index.js 中的代碼改成:// index.js
const name = "axuebin"
eslint 命令之后:
[no-unused-vars] 'name' is assigned a value but never used。定義了 name 變量卻未使用。 [quotes] Strings must use singlequote。字符串必須使用單引號(hào)。 [semi] Missing semicolon。缺失分號(hào)。
自動(dòng)修復(fù)
eslint xxx --fix 可以自動(dòng)修復(fù)一些代碼中的問(wèn)題,將無(wú)法自動(dòng)修復(fù)的問(wèn)題暴露出來(lái)。比如上文中提到的引號(hào)和分號(hào)的問(wèn)題,就可以通過(guò) --fix 自動(dòng)修復(fù),而 no-unused-vars 變量未使用的問(wèn)題,ESLint 就無(wú)法自動(dòng)修復(fù)。
使用配置包init 生成的配置文件中,我們看到包含這一行代碼:module.exports = {
extends: "eslint:recommended"
}
extends: 'xxx' 就是 繼承,當(dāng)前的配置繼承于 xxx 的配置,在此基礎(chǔ)上進(jìn)行擴(kuò)展。eslint-config 關(guān)鍵詞獲取,本文我們將這類封裝好的配置稱作 “配置集”。比較常見(jiàn)的配置包有以下幾個(gè):eslint-config-airbnb: Airbnb 公司提供的配置集 eslint-config-prettier: 使用這個(gè)配置集,會(huì)關(guān)閉一些可能與 Prettier 沖突的規(guī)則 eslint-config-react: create react app 使用的配置集 eslint-config-vue: vuejs 使用的配置集 ...
最佳實(shí)踐
抽象配置集
extends 三方配置集的基礎(chǔ)上,再手動(dòng)在 rules 配置里加一些自定義的規(guī)則。時(shí)間長(zhǎng)了,有可能 A 應(yīng)用和 B 應(yīng)用里的 rules 就不一樣了,就很難達(dá)到統(tǒng)一的目的。技術(shù)選型不一致:框架上 PC 使用 React,H5 使用 Vue;是否使用 TypeScript 跨端場(chǎng)景多:Web 端和小程序端,還有 Node ...

開(kāi)發(fā)插件
腳手架 / CLI 工具
詢問(wèn)用戶當(dāng)前項(xiàng)目的類型(是 JavaScript 還是 TypeScript、是 React 還是 Vue) 根據(jù)項(xiàng)目類型寫 .eslintrc.js文件根據(jù)項(xiàng)目類型安裝所需依賴(比如 vue 需要 eslint-plugin-vue) 在 package.json的scripts中寫入"lint": "eslint src test --fix"
const path = require('path');
const fs = require('fs');
const chalk = require('chalk');
const spawn = require('cross-spawn');
const { askForLanguage, askForFrame } = require('./ask');
const { eslintrcConfig, needDeps } = require('./config');
module.exports = async () => {
const language = await askForLanguage();
const frame = await askForFrame();
let type = language;
if (frame) {
type += `/${frame}`;
}
fs.writeFileSync(
path.join(process.cwd(), '.eslintrc.js'),
`// Documentation\n// https://github.com/axuebin/eslint-config-axuebin\nmodule.exports = ${JSON.stringify(
eslintrcConfig(type),
null,
2
)}`
);
const deps = needDeps.javascript;
if (language === 'typescript') {
deps.concat(needDeps.typescript);
}
if (frame) {
deps.concat(needDeps[frame]);
}
spawn.sync('npm', ['install', ...deps, '--save'], { stdio: 'inherit' });
};
axblint eslint 即可,如圖:
開(kāi)發(fā)時(shí):依賴編輯器的能力 手動(dòng)運(yùn)行:在終端中手動(dòng)執(zhí)行 eslint 命令 pre-commit:在提交 git 前自動(dòng)執(zhí)行 eslint 命令 ci:依賴 git 的持續(xù)集成,可以將檢查結(jié)果輸出文件上傳到服務(wù)器
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": "eslint --cache --fix"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
}
}


總結(jié)

評(píng)論
圖片
表情
