RexHung's Blog

塵世中一個前端迷途小書僮!

0%

[Tool Note] — ESLint v9 大更新隨手記

Introduction & 前言

Banner

你的專案正在使用 ESLint 嗎?

舊的 Config 無法在新版本使用了你知道嗎?新版本也不支援 Node.js v19 以前的版本了

這是一篇關於升級到 9.x 版本的紀錄,有興趣的話可以繼續往下看,這篇比較大篇幅可能都會在筆者的操作心得,不會有太多講解

如果你的專案還沒有使用 ESLint 可以參考筆者的這篇文章 [Next Note] - 把 TypeScript、ESLint、Prettier、Alias 摻再一起做沙尿牛丸

整篇文章是筆者自己的心得,如果文內有錯誤的地方,還請盡情指出。

本篇文章將會有兩個路線,一個是舊專案升級,一個則是新專案建立,可以依照自己所需在下面目錄跳轉


Summary & 摘要

本篇文章預設學習前的基本條件需求:

  • 知道 ESLint 在做什麼
  • 會使用終端機安裝套件
  • 一顆熱忱的心 -> 超級重要,碰到坑千萬不要氣餒

本篇文章將有以下幾個步驟:

  1. 前前前言
  2. 舊專案升級
  3. 新專案安裝
  4. 額外問題

前前前言

最近剛好同事搬移了一個新專案,由於一些前端的套件設定同事都是直接複製過去的,在筆者實際進行操作後,發現有一些東西沒有執行,查看之後才發現有些東西設定壞掉以及根本沒有啟用

因為 ESLint 同事是直接複製舊專案的設定檔案過去,但是跑安裝時候 ESLint 安裝了新版本,導致筆者想跑 lint 檢查時,出現錯誤,也就有了這篇文章

關於升級的部分可以參考官方文件解說,在 2023 年九月官方就有發文 Preparing your custom rules for ESLint v9.0.0

No longer maintained

如果到官網也能發現上面顯示 ESLint v8.x reached end-of-life on 2024-10-05 and is no longer maintained. Upgrade or consider long-term support options ,表示 2024-10-05 開始就不在維護 v8.x 版本了,甚至以下的版本都盡量不要再使用了

Meme

但如果舊專案跑的好好的就不要去動它了

再次提醒,如果要升級或使用的專案環境正在使用 Node.js v19 以前版本,也不要升級或使用 ESLint v9.x 之後(包含)版本了,前面有提到 新版本也不支援 **Node.js v19** 以前的版本了

本篇文章也大篇幅參考 稀土掘金 - 无聊波波ESLint 9.0大版本发布,配置文件大更新

這次更新主要是因為設定檔的方式改了,新版本改為 Flat Config(註1) 配置,可以理解為平面配置,會比原本的配置更簡單更好懂,另外也從 CJS 轉到 ESM (註2)

一些重大的更新可以參考 ESLint 官方的 Migrate to v9.x

註1:ESLint’s new config system, Part 2: Introduction to flat config

註2:【程式語言 - Javascript】 ESM與CJS


舊專案升級

如果你是新專案可以跳過這塊,直接看 新專案安裝

ESLint couldn't find an eslint.config

這次筆者在跑 lint 的時候出現圖上的錯誤,上面顯示 ESLintIgnoreWarning: The “eslintignore” file is no longer supported. ,然後在下面也可以看到 ESLint couldn’t find an eslint.config.(js|mjs|cjs) file.

沒錯,在 v9.x 版本開始不在使用 .eslintignore 也不在使用 .eslintrc.*

在內容有說到,如果你有原本使用的 .eslintrc.* 可以參考網址 https://eslint.org/docs/latest/use/configure/migration-guide 一文的 Configuration Migration Guide

If you are using a .eslintrc. file, please follow the migration guide to update your configuration file to the new format: https://eslint.org/docs/latest/use/configure/migration-guide*

基本上照的裡面的指令走不會有太大問題,所以這篇文章筆者不會放在多重點在怎麼操作,會大略帶過,如果有碰到什麼新問題會再放上來筆記

在新專案可以跑以下指令去執行轉換,請記得把後面的 .eslintrc.json 更換成你舊的配置檔案名稱,例如筆者舊的檔案叫做 .eslintrc.cjs,那指令就會變成 npx @eslint/migrate-config .eslintrc.cjs

1
npx  @eslint/migrate-config .eslintrc.json

npx 的意思是安裝後就會移除,我們只會使用當下那次

之後專案目錄就會出現新的檔案 eslint.config.mjs,依據你原本專案有在 .eslintrc.* 內配置的功能,這邊也會相對應幫你搬移過來一些設定

而舊的檔案就可以刪除了,另外也別忘記把 .eslintignore 刪除,現在新版本的設定全部都設定在 eslint.config.mjs 內即可

用升級的方式跟新專案的設定方式會有點不同,這邊先說說升級的方式要怎麼加入忽略檔案

以往我們都是透過 .eslintignore,而新升級的專案應該會是使用 globalIgnores 這個來自 eslint/config 套件的功能,升級時會自動安裝一些基本所必要的套件,所以不需要自己安裝

然後會有下面的寫法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { defineConfig, globalIgnores } from "eslint/config";
//...略

export default defineConfig([globalIgnores([
"**/node_modules/",
"**/build/",
"**/dist/",
"**/public/",
"**/postcss.config.js",
"**/tailwind.config.js",
"**/webpack.config.js",
"**/i18nTools.js",
"**/public",
"**/node_modules",
"**/jenkinsfile",
"params-script.cjs",
// 有一些你沒有的檔案可以自行刪除,例如 i18nTools.js
]), {
//... 略
}]);

之後有想新增的忽略檔案就直接加在那些字串後就好

之後我們去 package.json 新增兩行指令到 scripts

1
2
3
4
5
6
7
8
9
{
//...略
"scripts": {
//...略
"lint": "eslint . --ext .ts,.tsx,.js,.jsx",
"lint:fix": "eslint . --ext .ts,.tsx,.js,.jsx --fix",
},
//...略
}

然後跑以下指令

1
npm run lint

exports error

如果出現以上指令,代表你的設定檔有些問題,有可能你不是使用 ESMexport default ,而是使用 module.exports 需要去修改一下

Cannot find package

雖然前面有說,透過指令升級會幫你安裝所需要用到的套件,但是只是會幫你安裝基本必須會用到的套件,如果有跑出什麼套件找不到,還是需要手動安裝一下

像上圖出現 Cannot find package 'eslint-plugin-react' imported from /Users/xxxx 就是找不到之前配置所需要的套件,這邊需要手動安裝

之後都就緒沒問題,就可以跑測試,這次應該就會成功了

Run Lint


新專案安裝

新專案的話相對比較單純一點,可以參考 ESLint 官方的 Getting Started with ESLint

建立新專案的環境

1
2
3
mkdir eslint-9-test
cd eslint-9-test
npm init -y

初始化

1
npx eslint --init

期間依照你的專案環境或者使用的項目去回答他要你選擇的問題

回答結束後專案根目錄就會出現 eslint.config.mjs 這個檔案,打開它

這邊會發現新專案產生的設定跟舊專案升級的格式不太一樣,這邊比較單純一點就是一個陣列,有需要的設定就當成物件丟進去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { defineConfig } from "eslint/config";
import globals from "globals";
import js from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginReact from "eslint-plugin-react";

export default defineConfig([
{ files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"] },
{ files: ["**/*.js"], languageOptions: { sourceType: "commonjs" } },
{ files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"], languageOptions: { globals: globals.browser } },
{ files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"], plugins: { js }, extends: ["js/recommended"] },
tseslint.configs.recommended,
{
rules: {
quotes: ['error', 'single'],
eqeqeq: "off",
"no-unused-vars": "error",
"prefer-const": ["error", { "ignoreReadBeforeAssign": true }]

},
},
{
...pluginReact.configs.flat.recommended,
settings: {
react: {
version: "detect"
}
}
},
]);

Prettier 安裝

因為 ESLint 只會檢查錯誤,但是一些縮排等等的東西需要 Prettier 去達到,這邊有需要也可以另外安裝

1
npm i prettier eslint-config-prettier -D

記得要另外安裝 eslint-config-prettier 這個插件會禁用一些跟 Prettier 衝突的 ESLint 規則,也就是會以 Prettier 的為主

然後到 eslint.config.mjs 去新增設定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import eslintConfigPrettier from "eslint-config-prettier";

export default defineConfig([
//...略
eslintConfigPrettier, // 在中間隨機一行插入這個,但不要包在任何一個物件內
{
plugins: {
prettier: { // 設邊可以設定套件的規則
rules: {
// 开启这条规则后,会将prettier的校验规则传递给eslint,这样eslint就可以按照prettier的方式来进行代码格式的校验
'prettier/prettier': 'error',
// eslint(https://eslint.bootcss.com/docs/rules/)
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行
'no-console': 'error',
'no-debugger': 'error',
'no-unexpected-multiline': 'error', // 禁止空余的多行
'no-useless-escape': 'off', // 禁止不必要的转义字符

// typeScript (https://typescript-eslint.io/rules)
'@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量
'@typescript-eslint/prefer-ts-expect-error': 'error', // 禁止使用 @ts-ignore
'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。
'@typescript-eslint/semi': 'off',

// eslint-plugin-vue (https://eslint.vuejs.org/rules/)
'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用
'vue/no-mutating-props': 'off', // 不允许组件 prop的改变
'vue/attribute-hyphenation': 'off', // 对模板中的自定义组件强制执行属性命名样式
},
ignores: [
"node_modules",
"dist",
"build",
"coverage",
'eslint.config.mjs',
]
}
}
},
]);

之後可以參考下面的 自動檢測錯誤儲存自動修正

都設定完可以跑跑看 npm run lint

另外你可能會聽到 eslint-plugin-prettier 這個套件,實際爬文之後,網路有提到這個套件並不會用到,筆者確實也沒有用到,可以不需要安裝,除非你真得有碰到需要使用的情況,差異詳情可參考 eslint-config-prettier和eslint-plugin-prettier有什么关系

這邊再次推一下可以看看筆者這篇 [Next Note] - 把 TypeScript、ESLint、Prettier、Alias 摻再一起做沙尿牛丸


額外問題

自動檢測錯誤

如果你想要在寫程式的時候就自動檢測錯誤,也剛好你使用的是 VSCode 的話,請在專案本地打開設定

Mac 的快捷鍵為 Command + PWindows 則是 Ctrl + Shift + P

然後在輸入框中輸入 >Settings,接著選擇 喜好設定:開啟工作區設定

Open Settings

切記不要選擇到 喜好設定:開啟使用者設定(JSON),這個設定是針對這台電腦全部的專案設定

Click Icon

然後點擊右方的 檔案箭頭 Icon 會出現一個空白檔案,除非你的專案資料夾根目錄底下已經有 .vscode/settings.json

這時候貼上

1
2
3
4
{
"eslint.enable": true,
"eslint.run": "onType",
}

ESLint show error

這時候就能看到紅色蚯蚓出現了,如果沒有請關掉專案重新打開

VSCode Settings

請記得看專案根目錄是不是有出現這個檔案,之後建議這個檔案也要推上去 git ,其他一起共同開發的工程師才能用到一樣的設定

儲存自動修正

如果每次我們都需要跑 eslint . --ext .ts,.tsx,.js,.jsx --fix 才能修正檔案,未免效率也太低了些

這時候我們可以在 .vscode/settings.json 內加入以下兩個設定並儲存

1
2
3
4
5
6
7
8
{
//...略
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "always"
},
//...略
}

Auto fix

之後一儲存就會自動修正你有設定的 Rule 錯誤啦,但有一些比較麻煩一點的可能還是需要手動去修正

not include this file

沒有找到該檔案被包含在內的錯誤

如果出現上圖錯誤,很大概率是你的某個檔案有被 ESLint 檢測到錯誤,但他無法自動修正

如果你不想到那個檔案被檢測,可以在上面提到的忽略檔案內加入,例如你的 ESLint 配置檔案不想要被 ESLint 規則所束縛,那就在下面新增 **/eslint.*

1
2
3
4
5
6
7
8
9
10
import { defineConfig, globalIgnores } from "eslint/config";
//...略

export default defineConfig([globalIgnores([
//...略
"**/eslint.*",
// 有一些你沒有的檔案可以自行刪除,例如 i18nTools.js
]), {
//... 略
}]);

配置的寫法

配置寫法可先參考 稀土掘金 - KirkLinESLint配置文件有新写法啦,ESLINT FLAT CONFIG,筆者有記錄會補充上來


Conclusion & 結論

這次新專案設定 ESLint 算是又重新跑了一次流程,重新喚起一些以前的記憶,但前端似乎趨勢就是這樣,更迭的很快

舉例最近 CRA(註3) 也被官方廢除了,可參考 Sunsetting Create React AppCreate React App 的終結:為何被淘汰及 Vite 的崛起,我還記得不久之前開始寫 React.js 都還是用 CRA

這種筆記文章日後應該還是會很常出現,畢竟停下來一陣子就可能會突然落後別人好遠

No more update

求別再更新啦!!!!

希望這個筆記可以幫助到你,也能讓日後的我喚回一些記憶,日後也會慢慢更新碰到的問題

如果你有疑問也歡迎在下面留言一起討論

註3:CRA 是 React.js 官方釋出的一套轉譯工具,旨在讓使用者可以快速建構 React.js 環境,並且進行開發


參考網站