一、eslint介紹
ESLint 是一個開源的 JavaScript 代碼檢查工具,由 Nicholas C. Zakas 於2013年6月創建。代碼檢查是一種靜態的分析,常用於尋找有問題的模式或者代碼,並且不依賴於具體的編碼風格。對大多數編程語言來說都會有代碼檢查,一般來說編譯程序會內置檢查工具。
JavaScript 是一個動態的弱類型語言,在開發中比較容易出錯。因爲沒有編譯程序,爲了尋找 JavaScript 代碼錯誤通常需要在執行過程中不斷調試。像 ESLint 這樣的可以讓程序員在編碼的過程中發現問題而不是在執行的過程中。
ESLint 的初衷是爲了讓程序員可以創建自己的檢測規則。ESLint 的所有規則都被設計成可插拔的。爲了便於人們使用,ESLint 內置了一些規則,當然,你可以在使用過程中自定義規則。所有的規則默認都是禁用的。
ESLint 使用 Node.js 編寫。
二、eslint配置
配置方式:
一般都採用.eslintrc.* 的配置文件進行配置, 如果放在項目的根目錄中,則會作用於整個項目。如果在項目的子目錄中也包含着.eslintrc文件,則對於子目錄中文件的檢查會忽略掉根目錄中的配置,而直接採用子目錄中的配置,這就能夠在不同的目錄範圍內應用不同的檢查規則,顯得比較靈活。ESLint採用逐級向上查找的方式查找.eslintrc.*文件,當找到帶有 “root”: true 配置項的.eslintrc.* 文件時,將會停止向上查找。
在 package.json文件裏的 eslintConfig 字段進行配置。
具體配置規則:
module.exports = {
parser: 'babel-eslint', // parser指定解析器,默認的爲espree。babel-eslint是一個Babel parser的包裝器,這個包裝器使得 Babel parser 可以和 ESLint 協調工作
parserOptions: {
ecmaVersion: 6,
sourceType: 'module', // 設置爲 "script" (默認) 或 "module"(ES6)。
ecmaFeatures: { // 這是個對象,表示你想使用的額外的語言特性:
jsx: true // 啓用 JSX
}
},
extends: ['eslint:recommended'], // 使用eslint推薦的規則作爲基礎配置,可以在rules中覆蓋
plugins: ['html', 'vue', 'prettier', 'import'], // vue是eslint-plugin-vue的簡寫,此插件的作用是可以讓eslint識別.vue中的script代碼
rules: { // 0或者off表示規則關閉,出錯也被忽略;1或者warn表示如果出錯會給出警告(不會導致程序退出);2或者error表示如果出錯會報出錯誤(會導致程序退出,退出碼是1)
'no-console': 'off',
'prefer-const': 'error',
'prettier/prettier': 'warn',
'prefer-arrow-callback': 'warn',
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
},
globals: { // 允許在代碼中使用全局變量
location: true,
setTimeout: true
}
};
詳情:配置eslint
引入規則方式:
1、推薦規則:“extends”引入推薦規則
2、自定義規則以文件形式引入其它的自定義規則,
3、用rules去定義個別規則,可覆蓋掉”extends”中引入的規則。
{
"extends": [
"./node_modules/coding-standard/eslintDefaults.js",
// Override eslintDefaults.js
"./node_modules/coding-standard/.eslintrc-es6",
// Override .eslintrc-es6
"./node_modules/coding-standard/.eslintrc-jsx",
],
"rules": {
"eqeqeq": "warn"
}
}
4、註釋配置規則:代碼文件內以註釋配置的規則會覆蓋配置文件裏的規則,即優先級要更高。常用的就是 `eslint-disable-next-line(忽略掉下一行的lint報錯)
/* eslint-disable no-alert, no-console */
alert('foo');
console.log('bar');
/* eslint-enable no-alert, no-console */
三、忽略檢查
1、項目目錄下建立.eslintignore文件,並在其中配置忽略掉對哪些文件的檢查。需要注意的是,不管你有沒有在.eslintignore中進行配置,eslint都會默認忽略掉對/node_modules/** 的檢查。
2、在package.json文件的 eslintIgnore 字段進行配置
四、eslint檢查原理
大部分編譯器工作時的三個階段
解析:將未經處理的代碼解析成更爲抽象的表達式,通常爲抽象語法樹,即 AST。
轉換:通過修改解析後的代碼表達式,將其轉換爲符合預期的新格式。
代碼生成:將轉換後的表達式生成爲新的目標代碼。
對於eslint來說,規則校驗發生在將JavaScript 代碼解析爲 AST 之後,遍歷 AST 的過程中。eslint採用 Espree 來生成AST。
code path
指的是程序的執行路徑。程序可以由若干 code path 表達,一個 code path 可能包括兩種類型的對象 CodePath 和CodePathSegment。
ESLint的規則可以使用代碼路徑。代碼路徑是程序的執行路徑。
if (a && b) {
foo();
}
bar();
如果 a 爲真 - 檢測 b 是否爲 真
如果 b 爲真 — 執行 foo() — 執行 bar()
如果 b 非真 — 執行 bar()
如果 a 非真,執行 bar()
轉換爲 AST 的表達方式
ESLint 將 code path 抽象爲 5 個事件。
- onCodePathStart:
- onCodePathEnd
- onCodePathSegmentStart
- onCodePathSegmentEnd
- onCodePathSegmentLoop
可參考源碼 code-path-analyzer.js,官方文檔中 Code Path Analysis Details 中對 JS 中的 code path 也有很詳細的描述,可以參考。
rules工作原理
eslint中的rules源碼存在於lib/rules下。
每一個rules都是一個node模塊,用module.exports導出一個meta對象及一個create函數。
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow unnecessary semicolons",
category: "Possible Errors",
recommended: true,
url: "https://eslint.org/docs/rules/no-extra-semi"
},
fixable: "code",
schema: [] // no options
},
create: function(context) {
return {
// callback functions
};
}
};
meta 代表了這條規則的元數據,如這條規則的類別,文檔,可接收的參數 schema 等等。
create 返回一個對象,其中定義了一些在 AST 遍歷訪問到對應節點需要執行的方法等等。函數接受一個context對象作爲參數,裏面包含了例如可以報告錯誤或者警告的context.report()、可以獲取源代碼的context.getSourceCode()等方法,可以簡化規則的編寫。詳情:使用規則
五、如何自定義rules
栗子🌰:禁止塊級註釋,當代碼中使用了塊級註釋,eslint將報錯。
// lib/rules/no-block-comments.js
module.exports = {
meta: {
docs: {
description: '禁止塊級註釋',
category: 'Stylistic Issues',
recommended: true
}
},
create (context) {
// 獲取源代碼
const sourceCode = context.getSourceCode()
return {
Program () {
// 獲取源代碼中所有的註釋
const comments = sourceCode.getAllComments()
const blockComments = comments.filter(({ type }) => type === 'Block')
blockComments.length && context.report({
node: node,
message: 'No block comments'
})
}
}
}
}
如何使用自定義的rules
編寫好的rules需要發佈到npm上,作爲一個eslint-plugin,在項目中下載下來才能夠使用
no-block-comments.js
module.exports = {
"extends": ["../../eslintrc.vue.js"],
"plugins": [
"no-block-comments"// 可省略eslint-plugin
],
"rules": {
"no-block-comments/no-block-comments": 1 //// 引用no-block-comments插件中的no-block-comments規則
}
};
main.js
/**
* @author Renlingling
* @date 2019-08-26
* @Description:
*/
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
components: {App},
template: '<App/>',
})
結果:
/Users/renlingling/eslint-config-sgfe/tests/my-project/src/main.js
3:1 warning No block comments no-block-comments/no-block-comments