Create My Own ESLint Config Package !
為了維護專案的程式品質,避免不同開發者放飛自我,ESLint 基本是每個專案必備的套件,透過 ESLint 可以規範整個團隊的開發風格和程式碼品質,也能降低新進開發者進專案的時間成本。學會了 ESLint,也可以嘗試實作 Stylelint,做法也是一樣的~
為什麼要將 ESLint Config 獨立出來?
如果公司的需求,是常常需要開新的專案,這樣每次都需要設定(複製)一份 ESLint Config,且如果團隊規範的規則更改的話,需要至各至專案內更改,一來太繁瑣,二來也怕規則沒正確同步。
為了解決上述問題和更有效管理團隊規範,可以把 ESLint Config 打包成一個獨立套件,每個新開專案只要負責安裝套件、套用該規則即可~
Configuring ESLint 配置選項
下面例子為 vue-cli 創建專案時,所產出來的 ESLint Config 檔案,藉此我們會探討一些常見的配置選項。
// .eslintrc.js
module.exports = {
    root: true,
    env: {
      "node": true
    },
    parserOptions: {
      "parser": "babel-eslint"
    },
    extends: [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    plugins: [],
    rules: {},
};
- root
默認情況下,ESLint 會在所有父級目錄裡尋找配置文件,一直到根目錄,適合所有項目都遵循一個特定的約定時。
如果想 ESLint 限制到一個特定的項目,可設置 "root": true,表示當前配置文件為 eslint 的根配置文件,使其停止在父級目錄繼續尋找,效果如下:
home
└── user
    ├── .eslintrc
    └── projectA
        ├── .eslintrc  <- Not used
        └── lib
            ├── .eslintrc  <- { "root": true }
            └── main.js
- env
運行環境,用於定義全域變數,常見如下:
- browser : 瀏覽器環境中的全域變數
 - node : Node.js 全域變數和 Node.js 作用域
 - mocha : 添加所有的 Mocha 測試全域變數
 
- parserOptions
解析器的配置選項,可以指定想要的 ECMAScript 版本等資訊。
// 官網範例
 "parserOptions": {
      "ecmaVersion": 6, // 支持的ES語法版本,默認為5
      "sourceType": "module", // 指定JS代碼來源的類型,默認為script
      "ecmaFeatures": { // 表示你想使用的額外的語言特性
          "jsx": true // 啟用jsx語法
    }
},
更多資訊
parserOptions 的官方配置參數是不包括 parser 的,這裡會出現是因為使用 Vue 原因,詳情可參考這篇。
parserOptions: {
  "parser": "babel-eslint"
},
- extends
- 規則繼承,可繼承別人定義好的 eslint config 檔案。
 - 設定檔命名規則基本為 
eslint-config-*為前綴,在 extends 時可以把前綴省略。 
// .eslintrc.js
extends: [
    // 由 plugin 提供的設定檔(ESLint config)就要加上 `plugin:` 的前綴
    "plugin:vue/essential",
    // 套件為 eslint-config-prettier,前綴 `eslint-config` 可省略
    "prettier"
],
💡補充:
有些 plugin 會提供 ESLint config 給使用者做選擇。
plugin:vue/essential 是繼承 eslint-plugin-vue 中 config/essential.js (eslint config) 中的規則設定。
// 官方 repo 中的 essential.js
module.exports = {
  extends: require.resolve('./base'),
  rules: {
    'vue/no-arrow-functions-in-watch': 'error',
    'vue/no-async-in-computed-properties': 'error',
    ...}
}
- plugins
- 其他開發者定義的新規則,掛載至 plugin 後,使用者要自行決定如何去使用這些規則。
 - 命名規則為 
eslint-plugin-*為前綴,在擴充 plugin 時可以把前綴省略。 
// .eslintrc.js
rules: {
    // enforce tag names to pascal case
    "vue/component-name-in-template-casing": [
      "error",
      "PascalCase",
      {
        registeredComponentsOnly: false,
        ignores: ["/^router-/", "/^keep-/", "/^transition-/"],
      },
    ],
  },
上面例子為 eslint-plugin-vue 提供的規則 - 強制組件大寫命名 (vue/component-name-in-template-casing),需要在 rules 開啟設定,更多設定可以參考 eslint-plugin-vue 官網文件。
- rules
自定義規則,可擴展(或覆蓋)其他規則,後面規則會覆蓋前面的。
💡補充:
一般規則可到 ESLint 官網查詢,如果是 xxx/aaa 這些開頭的規則,是 xxx plugin 自訂的規則,需到相對應插件的官網查看。
創建 ESLint Config Package
這是一份常見的 package.json 檔案,其中包含 ESLint config 檔案,我們會嘗試把 ESLint config 抽出來成為獨立的 package。

Step 1. 新增空資料夾 & 初始化 npm
// 新增空資料夾
$ mkdir eslint-config-demo
$ cd eslint-config-demo
// 初始化 npm
$ npm init
⚠️ 注意:
檔名一定要 eslint-config-*,否則無法被 ESLint 讀取成功。
初始化完後,會得到一個 package.json 檔案。
// package.json
{
  "name": "eslint-config-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
Step 2. 新增 eslint 相關的 devDependencies 至 package.json
// package.json
{
  ...,
  "peerDependencies": {
    "@vue/cli-plugin-eslint": "~4.5.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2"
  },
  "devDependencies": {
    "@vue/cli-plugin-eslint": "~4.5.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2"
  }
}
官網 有提及如果設定檔案有依賴 plugin 的話可設定成 peerDependency。
peerDependencies 的目的是提示宿主環境去安裝滿足插件 peerDependencies 所指定依賴的包,永遠都是引用宿主環境統一安裝的 npm 包。
Step 3. 新增 .eslintrc.js
設定 eslint config,內容與 package.json 中的 eslintConfig 相同,但這裡需要用 module 寫法,如果有其他規則要添加,都可以撰寫至這份檔案中。
// .eslintrc.js
module.exports = {
    root: true,
    env: {
      "node": true
    },
    extends: [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    parserOptions: {
      "parser": "babel-eslint"
    },
    rules: {
      // 禁止使用 var
      "no-var": "error"
    }
};
Step 4. 新增 index.js
為 package 的入口檔案, 本體是 .eslintrc.js。
// index.js
const eslintrc = require('./.eslintrc.js');
module.exports = eslintrc;
Step 5. 補上 lock 檔 和 .gitignore
- 
install 完,取得 lock 檔案
$ npm run install $ yarn - 
新增
.gitignore// .gitignore node_modules/ 
Step 6. 完成陽春版的 ESLint Config 檔案了!
- eslint-config-demo 的 Repository
 

使用 ESLint Config Package
Step 1. 安裝
可以使用下述 local、github 和 npm 三種方法安裝 package:
- local
// npm i -D {{ 本機檔案路徑 }}
$ npm i -D ../eslint-config-demo
$ yarn add -D ../eslint-config-demo
- github
// npm i -D {{ git + github 網址 }}
$ npm i -D git+https://github.com/JennieSH/eslint-config-demo.git
$ yarn add -D git+https://github.com/JennieSH/eslint-config-demo.git
💡補充
如果有特定版號需求,可以在 github 網址後加指定版號
$ npm i -D git+https://github.com/JennieSH/eslint-config-demo.git#v.1.0.0
- npm (需要先在 npmjs 上架,才能下載)
💡補充參考
// npm i -D {{ 套件名稱 }}
$ npm i -D eslint-config-demo
$ yarn add -D eslint-config-demo
❗注意
如果是使用 peerDependencies 方法,要確定專案(宿主)內,相關依賴的的套件都需要被安裝。
💡補充
如果是在 npm 上架過的 package,且 npm 版本大於 5,可以使用 npx install-peerdeps,一個指令就可以自動安裝全部的 peerDependencies。
- npm
 
npx install-peerdeps --dev eslint-config-demo
- yarn
 
npx install-peerdeps --dev eslint-config-demo -Y
Step 2. 設定專案內的 .eslintrc.js 檔案
在專案的 ESLint 設定檔內 extends 目標套件,其 eslint-config-* 前綴可省略。
// .eslintrc.js
{
  ...,
  "extends": [ "demo" ]
}
因為在設定檔的 rules 中有設置 "no-var": "error",完成 extends 設定後,就可以看到 eslint 報錯了~如果沒反應的話,VS Code 請重新啟動試試!

Step 3. VS Code 設定
基本的 ESLint Config Package 使用設定在第 2 步驟時就已經完成了。
如果想進一步,針對一些簡單錯誤,存檔後能自動修正,需要再調整 VS Code 設定。
- 確保 VS Code 有安裝 ESLint Extension
 - 新增 
settings.json至.vscode資料夾 
// settings.json
{
  // These are all my auto-save configs
  "editor.formatOnSave": true,
  // turn it off for JS and JSX, we will do this via eslint
  "[javascript]": {
    "editor.formatOnSave": false
  },
  "[javascriptreact]": {
    "editor.formatOnSave": false
  },
  // show eslint icon at bottom toolbar
  "eslint.alwaysShowStatus": true,
  // tell the ESLint plugin to run on save
  "editor.codeActionsOnSave": {
    "source.fixAll": true
  }
}
如果無正常運作的話,請麻煩重啟 VS Code 試試!
參考資料
- 這可能是 vue 中 eslintrc.js 最詳細的介紹了
 - How to Create Your Own ESLint Config Package
 - 建立公司內部使用的 eslint-config package
 - ESLint 官網
 - GitHub: eslint-config-wesbo
 
