內容非常詳細!領略 Eslint 代碼檢查的四種姿勢

前言:記得我剛開始參與到公司項目的開發時,由於代碼結構太亂被同事集體 diss,而後被強烈要求打開 eslint 來開發,無奈之下陷入 eslint 的魔爪。但是當我打開 eslint 的時候,我真的是去他喵的,代碼哪哪都給我爆紅,然後我就偷偷把 eslint 關掉了(機智如我 <( ̄︶ ̄)>)。但是,果不其然,沒過多久我就又被抓住了。在經歷了幾次貓抓老鼠的遊戲之後,我終於習慣並且喜歡上 eslint 了。

在這篇文章中,我不會花太多的筆墨去介紹 Eslint 的使用,因爲那是官方文檔該做的事情。我所希望做到的是,在閣下看完這篇文章之後,能夠超脫於 Eslint 本身,去看到它所實現的需求本身,即實現 js/ts 的代碼檢查。而後,我會以實現代碼檢查這個需求爲出發點,引出代碼 eslint 的四種代碼檢查姿勢

對於代碼檢查需求及其實現方案,我從個人認識出發,用腦圖做了以下整理:

接下來的行文,我都會圍繞這副腦圖展開,如果您有興趣繼續往下看下去,我希望您能在這幅圖上停留多一些時間。

好的,按照上述腦圖中的邏輯,接下來我會分成以下幾個部分來展開探討本文。

好的,理清了行文思路之後,下面我們進入第一部分,理解代碼檢查。

一:理解代碼檢查

代碼檢查,顧名思義就是檢查代碼,發生於開發階段,可有效幫助開發者減少 JavaScript 粗心代碼,如語法錯誤、變量未定義、變量未使用等等問題。除此之外,代碼檢查還可以約束統一開發人員的代碼風格,利於團隊協作。

經過上面這段話,我們就已經達成了對代碼檢查的概念理解。下面我們再從三個方面來展開分析,加深對代碼檢查的實踐理解。這三個方面分別爲以下三點:

好的,下面我們就先進入代碼檢查功能的探討。

1. 代碼檢查的功能

我認爲,代碼檢查這個切面大概可以幫助我們做以下三件事情:

文外總結:切面所在層次,決定了該切面的職能上線。

理解了代碼檢查這個切面所可以實現的功能之後,下面我們就探討一下代碼檢查的類型。

2. 代碼檢查的方式

以代碼檢查發生的不同時間和場景來劃分,我把代碼檢查的方式分類成以下四種:

如此無私分享,不值得你的點贊和關注鼓勵一下嗎?

理解代碼檢查的方式很重要,這直接反映了你對代碼檢查這個概念本身的掌握程度。廢話不多說,下面我們進入代碼檢查工具的探討。

3. 代碼檢查工具

代碼檢查的實現通常不會僅僅是字符串分析處理,這其中會大量涉及到語法分析。既然涉及到語法,那麼就需要對不同的代碼使用不同的代碼檢查工具,通常來說,我們會使用 Eslint 工具來實現對 JavaScript 和 Typescript 代碼的檢查,使用 stylelint 工具對樣式代碼進行代碼檢查。對於 stylelint,本文不多做敘述,接下來我們把舞臺交給 Eslint,一起探討一下如何使用 Eslint 實現 JavaScript 代碼和 typescript 代碼的檢查。

好的,在按順序探討編碼後檢查、編碼時檢查、構建前檢查、git 提交前檢查這四種代碼檢查方式之前,我們先爲項目接入 Eslint,並配置各種代碼檢查方式都需要的檢查規則

二:爲項目接入 Eslint 實現代碼檢查

有不少朋友可能並不瞭解 Eslint,下面我們先對它做個簡單介紹。

Eslint 是一款插件(檢查規則)化的 JavaScript 代碼檢查工具。概念言簡意賅,需要注意的是,概念中說到 eslint 是一個插件化的檢查工具,其意思是指 eslint 的設計是把檢查工具和檢查規則之間解耦了。也就是說,在安裝好 eslint 的開發依賴之後,我們還可以並且需要選擇安裝一個我們中意的檢查規則

好的,理論就說到這,接下來我們就從實踐中得到真知,實踐步驟如下:

step1:安裝檢查工具 eslint

1yarn add eslint --dev
2
3

step2:安裝並配置檢查規則

在探討配置安裝檢查規則之前,我們有必要先明確一下我們的檢查目標是什麼。我認爲,檢查目標自然是構建前的代碼,並且是自己 / 自己團隊編寫的代碼(非第三方模塊)。畢竟檢查的最終目標是爲修復服務的,我們只負責修復自己 / 自己團隊編寫的代碼,構建後代碼以及第三方代碼即使檢查不通過我們也不會也不應該由我們去修復。

檢查規則在項目中通常有兩種表現形式,即:

生成 eslint 配置文件:

對於配置文件,我們通常會使用 eslint --init 命令來生成這個配置文件,下表列舉了一些調用這個命令之後經常出現的配置問題(不一定會是依次下面幾個問題)。

注意:我覺得回答這些問題還是要慎重一些,因爲問題答案會影響配置,配置會影響檢查規則,檢查規則會影響檢查結果。當然,回答這些問題的目的也就是生成想要配置文件,如果問題回答錯了或者後續對規則有改動也可以直接修改 eslint 配置文件

代碼中的魔法註釋寫法:

除了配置文件中配置規則,eslint 還有一個代碼中通過魔法註釋打規則補丁的辦法,如下示例:

1// 屏蔽整行的代碼檢查
2const str1 = "${name} is a coder" // eslint-disable-line
3// 屏蔽某一個規則:如此行的no-template-curly-in-string規則
4const str1 = "${name} is a coder" // eslint-disable-line no-template-curly-in-string 
5

溫馨提示:規則名稱可以從檢查結果提示或輸出信息中得到

三:基於 Eslint 及其規則實現 <編碼後檢查>

對於一個工作流程的解釋,我還是更傾向於直接演示一個簡單的 demo。在這個行文思路下,下面我們就分別演示一個 Eslint 檢查 JS 代碼的示例以及一個 Eslint 檢查 TS 代碼的示例。根據代碼檢查的邏輯,demo 演示和講解時我會遵循以下思路,即:

好的,下面我們就進入 Eslint 對 JS 代碼編碼後檢查示例的探討。

1.Eslint 編碼後檢查 JS 代碼示例

1): 目標問題代碼

 1const noUsedVar = 1;
 2
 3function fn() {
 4  console.log('hello')
 5
 6  cnsole.log('eslint');
 7}
 8
 9fn(
10
11fn2();
12

以上短短几行代碼就可以表示出 eslit 代碼檢查的三個部分,它們分別是:

2): 代碼檢查規則配置

通過 eslint --init,根據項目特徵來回答問題之後得到的 eslint 配置文件如下:

 1module.exports = {
 2  env: {
 3    browser: true,
 4    es6: true,
 5  },
 6  extends: [
 7    'airbnb-base',
 8  ],
 9  globals: {
10    Atomics: 'readonly',
11    SharedArrayBuffer: 'readonly',
12  },
13  parserOptions: {
14    ecmaVersion: 2018,
15  },
16  rules: {
17  },
18};
19
20

3): 代碼檢查操作和結果

第一輪檢查結果先是報了語法錯誤,在修復語法錯誤之後,第二輪檢查報錯了很多編碼以及風格上的錯誤。將兩次檢查結果關聯到問題代碼可以得到如下分析:

 1const noUsedVar = 1; // find program:'noUsedVar' is assigned a value but never used
 2
 3function fn() {
 4  console.log('hello') // enforce code style:Missing semicolon(分號)
 5
 6  cnsole.log('eslint'); // find program:'cnsole' is not defined
 7}
 8
 9fn( // syntax error
10
11fn2(); // find program:'fn2' is not defined
12

4): 修復代碼

根據上述檢查結果進行修復。對於代碼風格上的不一致導致的錯誤,通過參數 --fix 即可以自動修復大部分的問題。而對於語法以及編碼上的錯誤則大部分只能是開發者自己手動修復。經過手動修復以及自動修復之後,問題代碼可能變爲如下模樣:

 1import { fn2 } from './test2';
 2
 3function fn() {
 4  console.log('hello');
 5
 6  console.log('eslint');
 7}
 8
 9fn();
10
11fn2();
12

2.Eslint 編碼後檢查 TS 代碼示例

1): 目標問題代碼

1function foo(ms: string): void{
2  console.log(msg);
3
4  }
5
6foo("hello typescript~")
7

2): 代碼檢查規則配置

項目安裝 typescript 依賴後(不先安裝 typescript 依賴就執行 eslint --init 會報錯),通過 eslint --init 命令,根據項目特徵來回答問題(typesrcipt yes)之後得到的 eslint 配置文件如下:

 1module.exports = {
 2    "env": {
 3        "browser": true,
 4        "es6": true
 5    },
 6    "extends": [
 7        "airbnb-base"
 8    ],
 9    "globals": {
10        "Atomics": "readonly",
11        "SharedArrayBuffer": "readonly"
12    },
13    "parser": "@typescript-eslint/parser",
14    "parserOptions": {
15        "ecmaVersion": 2018
16    },
17    "plugins": [
18        "@typescript-eslint"
19    ],
20    "rules": {
21    }
22};
23
24

相對於 JavaScript 的代碼檢查,對於 typescript 的檢查需要額外的一個語法解析器(即上述配置中的 parser 配置項內容)。

3): 代碼檢查操作和結果

eslint 以 --fix 參數檢查之後,主要報了兩個編碼錯誤,映射到文件中分析如下:

1function foo(ms: string): void { // 'ms' is defined but never used 
2  console.log(msg); // 'msg' is not defined
3}
4
5foo('hello typescript~');
6

4): 修復代碼

在本示例中,在 fix 自動修復代碼風格之後,手動把 foo 函數的形參改爲 msg 即可。

1function foo(msg: string): void {
2  console.log(msg);
3}
4
5foo('hello typescript~');
6

四:基於 Eslint 及其規則實現 <編碼時檢查>

說到編碼時檢查就不得不提到代碼提示,也不得不聯繫到我們所具體選擇使用的 IDE。除此之外,爲了保證多種方式下代碼檢查規則的統一配置,我們還需要做到的關鍵一點是 IDE 能夠讀取我們在項目中配置的 eslint 規則文件去實時檢查代碼

由於個人主要使用 VScode 開發,所以下面做的 demo 和探討都默認在 vscode 環境下。官方相關資料:Eslint 的官方整合工具列表中的 [1. 安裝 eslint、配置 eslint 規則](https://marketplace.visualstudio.com/items?item>Visual Studio Code: ESLint Extension 文檔。

說實話,這個東西我也是現學現賣,畢竟前端要學的東西實在太多了,而且這篇文章的初衷也不是對某一技術點的面面俱到,而是幫助你建立系統化認識以及引導。

由於我們需要做到在 IDE 實時代碼檢查時,能夠讀取讀取項目下的 eslint 規則。所以以下兩個步驟必不可少:

根據以上實現步驟思路,下面我們就做一個 vscode 環境下,基於 Eslint 及其規則實現編碼時檢查的 demo。

1. 安裝 eslint、配置 eslint 規則

1yarn add eslint --dev	# 安裝
2eslint --init	# 初始化配置
3
4

eslint 的規則配置方式上面已經討論過,這裏就不再展開贅述了。

2.IDE 實時代碼檢查功能相關安裝配置

在 eslint 工具以及檢查規則準備好之後(該規則就是 IDE 代碼檢查的規則),剩下的具體的檢查行爲觸發以及代碼提示工作就要交給 IDE 來實現了。對於 vscode,這裏我們的實現思路是安裝 eslint 這個擴展插件(個人使用的版本 2.1.14,下面的配置 1.x 很可能不適用),而後注意打開 vscode 的 eslint 代碼檢查功能(vscode 下的 eslint 開關爲右下角的 eslint 文字標識)即可實現 vscode 環境下的 eslint 實時代碼檢查。

配置 IDE 的實時檢查功能

如果需要對 IDE 的實時檢查功能做一些配置,則可以通過 打開 vscode 的 setting -> 找到 eslint -> 打開 setting.json 這幾個步驟來找到相關的配置文件,以下是配置 vscode 代碼檢查功能示例:

1//配置eslint
2    "editor.codeActionsOnSave": { // 保存時自動fix
3        "source.fixAll.eslint": true
4    },
5    "eslint.quiet": true,   // warning時不報紅色下劃線,可用於處理no-console規則爆的warning
6

實時代碼檢查報錯後的修復

在 IDE 自動檢查的過程中,報錯提示如果報的是代碼觸犯了規則的提示,那麼就可以修改項目下的檢查規則文件(.eslintrc.js)。比如個人在 demo 實踐中就遇到了 ESLintExpected linebreaks to be 'LF' but found 'CRLF'這個規則錯誤,並且它的情況還有些特殊,它在 IDE 實時檢查會報,但是手動調用 eslint 命令時不報,具體原因在此不多做分析,個人是直接在規則文件(.eslintrc.js)加入以下規則得以解決的:

1rules: {
2    'linebreak-style': [0, 'error', 'windows'],
3  },
4
5

五:基於 Eslint 及其規則實現 <構建前檢查>

下面我們直接進入現如今較爲常用的 gulp 以及 webpack 構建工具如何實現構建前檢查的探討。

1.gulp 構建前檢查

通過 gulp 實現這個代碼檢查切面的思路如下:

1): 初始化 eslint 配置文件

1yarn add eslint --dev
2eslint --init
3
4

2): 下載安裝 gulp-eslint 插件

1yarn add gulp-eslint --dev
2
3

3): 編寫 js 文件處理的代碼檢查切面

示例如下:

 1// ... 其它代碼
 2const eslint = require('gulp-eslint');
 3
 4const script = (0 => {
 5 return src(['scripts/*.js'])
 6         .pipe(eslint()) // 代碼檢查
 7         .pipe(eslint.format()) // 將lint結果輸出到控制檯。
 8         .pipe(eslint.failAfterError()) // lint錯誤,進程退出,結束構建。
 9         .pipe(babel({ presets: ['@babel/preset-env']}))
10         .pipe(dest('temp'))
11         .pipe(bs.reload( { stream: true } ))
12}
13// ... 其它代碼
14

2.webpack 構建前檢查

通過 webpack 來實現這個代碼檢查切面的思路如下:

(1): 安裝 eslint 並初始化 eslint 配置文件

1yarn add eslint --dev
2eslint --init
3
4

(2): 安裝 eslint-loader

1yarn add eslint-loader --dev
2
3

(3): 編寫 webpack 配置文件,爲 js 文件加上這個 eslint-loader

 1rules: [
 2 {
 3  test: /.js$/,
 4  exclude: /node_modules/,
 5  use: [
 6   'babel-loader',
 7   'eslint-loader' // 更後的先執行
 8  ]
 9 }
10]
11
12

六:基於 Eslint 及其規則實現 <git 提交前檢查>

這一個部分的講解,我接下來會從以下四個方面循序漸進的探討 Eslint 如何實現 git 的提交前檢查:

  1. 使用 husky 實現:編寫 node 代碼替代 shell 代碼

  2. 實現 hook 任務流:通過 lint-staged 來配合 husky 來實現

  3. 實現 git 提交前檢查:先執行 eslint 任務而後執行 git add 任務

下面我們進入第一點,git 提交前檢查原理:Git Hooks 的探討。

1.git 提交前檢查原理:Git Hooks

Eslint 實現 git 的提交前檢查是通過 Git Hooks 實現的,Git Hook 也稱之爲 git 鉤子,每個鉤子都對應一個任務,通過 shell 腳本可以編寫鉤子任務觸發時要具體執行的操作。

本文關注實現 git 提交前的代碼檢查,所以我們關注 git commit 這個鉤子,使用步驟如下:

1#!/bin/sh
2echo "before commit"
3
4

git commit 命令執行後,可以發現 commit 操作不管是否成功,都可以看到輸出的 before commit 信息。

上述方式可用但還在實際生產中使用還是不太合適,畢竟對於前端開發者來說,使用 shell 腳本編寫 git hook 的方式還是比較難接收,下面我們介紹 husky 這個庫的使用,幫助我們達成以 js 代碼的方式來編寫 hook 任務的目的。

2. 使用 husky 實現:編寫 node 代碼替代 shell 代碼

實現步驟如下:

1): 安裝 husky

1yarn add husky --dev
2
3

在安裝好這個模塊後,就可以在. git/hooks 文件夾下看到如下這些新添加的文件。

2): 配置 husky 的 hook 任務:如下 package.json 任務

 1"scripts": {
 2    "test1": "echo before commit",
 3    "test2": "node test2.js"
 4  },
 5  "husky": {
 6    "hooks": {
 7      "pre-commit": "yarn test2"
 8    }
 9  },
10
11

3): 觸發鉤子:git add -> git commit

git commit 命令執行後,就可以觸發我們通過 husky 實現的由 js 代碼編寫的 hook 任務。

下面我們增強一下,通過 lint-staged 這個庫,讓 hook 不但支持單任務還支持任務流的觸發。

3. 實現 hook 任務流:通過 lint-staged 來配合 husky 來實現

實現步驟如下:

1): 安裝 husky 和 lint-staged 模塊

1yarn add husky --dev
2yarn add lint-staged --dev
3
4

2): 配置 husky 的 hook 任務流:如下 package.json 任務

 1"scripts": {
 2    "precommit": "lint-staged"
 3},
 4"husky": {
 5    "hooks": {
 6        "pre-commit": "yarn precommit"
 7    }
 8},
 9"lint-staged": {
10 "*.js":[
11        "echo task1",
12        "echo task2",
13        "echo task3"
14 ]
15}
16
17

3): 觸發任務流:git add -> git commit

實踐發現,與單獨的 husky 模塊實現單任務相比而言,使用 lint-staged 之後,git commit 命令只有成功執行(有 add 資源並且有提交信息)纔會觸發 lint stage 中的操作,且這些操作只會對 js 文件有效。

好的,經過以上鋪墊,下面我們就可以進入我們所要實現的最終需求,即實現 git 提交前檢查的探討了。

4. 實現 git 提交前檢查:先執行 eslint 任務而後執行 git add 任務

實現步驟如下:

1): 安裝 husky 和 lint-staged 模塊

1yarn add husky --dev
2yarn add lint-staged --dev
3
4

2): 配置 husky 的 hook 任務流:如下 package.json 任務

 1"scripts": {
 2    "precommit": "lint-staged"
 3},
 4"husky": {
 5    "hooks": {
 6        "pre-commit": "yarn precommit"
 7    }
 8},
 9"lint-staged": {
10 "*.js":[
11        "eslint --fix",
12        "git add"
13 ]
14}
15
16

3): 觸發任務流:git add -> git commit

經過這些開發包的下載以及配置,在我們執行 git commit 之後,就會觸發 husky 配置的 pre-commit 的 hook 任務,而這個 hook 任務又把任務交給了 lint-staged 處理,進而通過 lint-staged 實現對 js 文件的代碼檢查以及自動風格修復後(還是錯誤則會中斷提交)重新 add,而後再執行 commit 任務,保證了代碼在提交前一定經過了代碼檢查。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/f6oau6PbpjtNmeKF5mVz8Q