知識0からESLintのFlat Configを導入してみる
この記事でできる事
- ESLintの導入〜Flat Configに対応した設定
- sampleコードを利用した
eslint
の実行と実行結果の確認
背景
YouTube 動画で ESLint に関して紹介している動画をいくつか見て、
便利さをなんとなく理解した状態で、早速 ESlint を導入してみようと思ったのですが、
どうやら ESLint の v9 から Flat Config なる物がデフォルトになり、
これまでとお作法が変わったということでした。
本記事では Flat Config を採用して、初心者がなんとか基本的な使い方を理解する所までの道のりを記しています。
ESLint とは
JavaScript のコードを解析し、構文エラーや、指定したルールに違反していないかをチェック/修正をしてくれる静的解析ツールです。
静的解析ツールとは
コードを実行せずに解析し、コードの品質や信頼性を検証する手法です。
つまり、プログラムが動く動かないの前に、
- 構文エラーのない、ちゃんとしたコードを書いている?
- プロジェクト固有のコーディング規則(指定したルール)に則って書けてる?
という事を確認してくれる素晴らしいツールです。
環境
eslint : 9.8.0
インストール方法
-
eslint を導入する任意のフォルダに移動
-
npm の初期化
npm init -y
-
開発環境に eslint をインストール
npm i -D eslint
eslint の初期化処理
npx eslint --init
>? How would you like to use ESLint? …
To check syntax only -- 構文チェックのみ
To check syntax and find problems -- 構文チェックと問題の発見
To check syntax and find problems
を選択。
構文だけでなく、様々な問題を発見してくれるようです(未定義の変数のチェックなど、本当に様々)
>? What type of modules does your project use? …
JavaScript modules (import/export)
CommonJS (require/exports)
None of these
JavaScript modules (import/export)
を選択
>? Which framework does your project use? …
React
Vue.js
None of these
任意の framework 選択
>? Does your project use TypeScript? …
No
Yes
TypeScript を利用していればYes
を選択
>? Where does your code run? … (Press <space> to select, <a> to toggle all, <i> to >invert selection)
✔ Browser
✔ Node
ESLint がどの環境でコードを実行するかを指定します。
- Browser を選択
ブラウザに特有グローバル変数(例えば、window や document など)を利用しても、Error になりません - Node を選択
すると、Node.js 特有のグローバル変数(例えば、module や process など)を利用しても、Error になりません
両方選択する場合はa
を押すと、両方にチェックが入ります。
>The config that you've selected requires the following dependencies:
eslint@9.x, globals, @eslint/js
? Would you like to install them now? › No / Yes
ESLint の設定に必要な依存関係(eslint@9.x, globals, @eslint/js)をインストールするかどうかを尋ねていますので、基本Yes
を選択して、インストールを行います。
>? Which package manager do you want to use? …
npm
yarn
pnpm
bun
任意 package manager を選択します。
eslint の設定 (eslint.config.mjs の設定)
初期処理で作成したeslint.config.mjs
に独自のルールを追加します。
様々なルールが存在するので、今回は Chat-GPT で確認したおすすめの設定を追加します。
import globals from "globals";
import pluginJs from "@eslint/js";
export default [
{
// 対象ファイルを指定し、グローバルな言語オプションを適用
files: ["**/*.js"], // 全ての階層の拡張子がjsファイルにeslintを適用
languageOptions: {
globals: globals.browser, // ブラウザ環境のグローバル変数を許可
},
ignores: ["before.js"], // 無視するファイルを指定
// 推奨設定を適用
...pluginJs.configs.recommended,
// カスタムルールを指定
rules: {
"no-unused-vars": ["error"], // 未使用の変数をエラーとして検出
"no-undef": ["error"], // 未定義の変数をエラーとして検出
eqeqeq: ["error", "always"], // 厳密な等価演算子を強制
"no-console": ["warn"], // console.log の使用を警告
indent: ["error", 4], // インデントを4スペースで強制
quotes: ["error", "single"], // シングルクォートを強制
semi: ["error", "always"], // セミコロンを必須に
"brace-style": ["error", "1tbs"], // ブレースのスタイルを "1tbs" に強制
camelcase: ["error", { properties: "always" }], // キャメルケースを強制
// "newline-after-var": ["error", "always"], // 変数宣言後の空行を強制(コメントアウト中)
"no-magic-numbers": ["warn", { ignore: [0, 1] }], // マジックナンバーの使用を警告
"consistent-return": ["error"], // 一貫した return を強制
"no-var": ["error"], // var の使用を禁止
complexity: ["warn", { max: 10 }], // 関数の複雑さを制限
"prefer-const": ["error"], // 再代入されない変数に const を推奨
// "import/no-unresolved": ["error"], // モジュールの解決をチェック(コメントアウト中)
},
},
];
eslint の実行
1. sample の準備
eslint.config.mjs に記述したルールから逸脱した内容のコードを、sample.js にまとめて記述して、実際に実行した時にどの様な結果になるかを確認していきます。
// 1. no-unused-vars ルール
function calculateSum(a, b) {
const unusedVar = 10; // no-unused-vars: 使われていない変数
const sum = a + b;
return sum;
}
calculateSum(1,2);
// 2. no-undef ルール
function printMessage() {
console.log(message); // no-undef: 'message' が未定義
}
printMessage();
// 3. eqeqeq ルール
function isEqual(x, y) {
if (x == y) { // eqeqeq: == を使用
return true;
}
return false;
}
isEqual(1,1);
// 4. no-console ルール
function logMessage(message) {
console.log(message); // no-console: console.log を使用
}
logMessage('message');
// 5. indent ルール
function greet(name) {
return 'Hello, ' + name; // indent: インデントが不正
}
greet('Hello World')
// 6. quotes ルール
function sayHello() {
const greeting = "Hello, World!"; // quotes: ダブルクォート使用
return greeting;
}
sayHello();
// 7. semi ルール
function getGreeting(name) {
return 'Hello, ' + name // semi: セミコロンがない
}
getGreeting('World');
// 8. brace-style ルール
function showMessage(condition) {
if (condition)
{ // brace-style: ブレースのスタイルが不正
console.log('Condition is true');
}
}
showMessage(true);
// 9. camelcase ルール
function process_data() { // camelcase: スネークケースが使用されている
const user_name = 'John Doe'; // camelcase: スネークケースが使用されている
return user_name;
}
process_data();
// 10. no-magic-numbers ルール
function calculateDiscount(price) {
return price * 0.8; // no-magic-numbers: マジックナンバー 0.8 が使用されている
}
calculateDiscount(100);
// 11. consistent-return ルール
function checkStatus(status) {
if (status === 'success') {
return true;
} else if (status === 'failure') {
return false;
} // consistent-return: 一貫性のない return
// else { 'success' or 'failure' に該当しない場合にundefinedが返されてしまう
// return null
// }
}
checkStatus('success');
// 12. no-var ルール
function displayMessage() {
var message = 'Hello!'; // `var` が使用されている
console.log(message);
}
displayMessage();
// 13. complexity ルール
// ネストが深くかつ、複雑な構成
function calculate(value) {
if (value > 10) {
if (value < 20) {
if (value % 2 === 0) {
if (value > 15) {
return 'Value is between 16 and 20 and even';
} else {
return 'Value is between 11 and 15 and even';
}
} else {
return 'Value is between 11 and 20 and odd';
}
} else {
if (value < 30) {
if (value % 2 === 0) {
return 'Value is between 21 and 30 and even';
} else {
return 'Value is between 21 and 30 and odd';
}
} else {
return 'Value is greater than 30';
}
}
} else {
return 'Value is 10 or less';
}
}
calculate(10);
// 14. prefer-const ルール
function getMessage(name) {
const message = 'Hello, ' + name; // prefer-const: この変数は再代入されないため、constを使用すべき
return message;
}
getMessage('hoge');
2. npx eslint の実行 (--fix オプションをつけずに実行)
npx eslint
上記コマンドを実行すると、eslint.config.mjs
に記述した内容に従って、チェックした結果が出力されます。
今回の sanple.js では 28 箇所で問題が確認されています。
オプションの --fix
をつけると、動作に影響の無い部分で自動的に 7 箇所修正してくれます。
✖ 28 problems (14 errors, 14 warnings)
7 errors and 0 warnings potentially fixable with the--fix
option.
ESlintTutorial/sample.js
3:11 error 'unusedVar' is assigned a value but never used no-unused-vars
7:16 warning No magic number: 2 no-magic-numbers
11:5 warning Unexpected console statement no-console
11:17 error 'message' is not defined no-undef
17:11 error Expected '===' and instead saw '==' eqeqeq
26:5 warning Unexpected console statement no-console
32:1 error Expected indentation of 4 spaces but found 0 indent
34:21 error Missing semicolon semi
38:22 error Strings must use singlequote quotes
45:28 error Missing semicolon semi
52:5 error Opening curly brace does not appear on the same line as controlling statement brace-style
53:9 warning Unexpected console statement no-console
59:10 error Identifier 'process_data' is not in camel case camelcase
60:11 error Identifier 'user_name' is not in camel case camelcase
61:12 error Identifier 'user_name' is not in camel case camelcase
67:20 warning No magic number: 0.8 no-magic-numbers
69:19 warning No magic number: 100 no-magic-numbers
72:10 error Expected to return a value at the end of function 'checkStatus' consistent-return
78:1 error Expected indentation of 4 spaces but found 8 indent
86:5 error Unexpected var, use let or const instead no-var
87:5 warning Unexpected console statement no-console
94:17 warning No magic number: 10 no-magic-numbers
95:21 warning No magic number: 20 no-magic-numbers
96:25 warning No magic number: 2 no-magic-numbers
97:29 warning No magic number: 15 no-magic-numbers
106:25 warning No magic number: 30 no-magic-numbers
107:29 warning No magic number: 2 no-magic-numbers
120:11 warning No magic number: 10 no-magic-numbers
✖ 28 problems (14 errors, 14 warnings)
7 errors and 0 warnings potentially fixable with the `--fix` option.
2. --fix オプションをつけて実行
npx eslint --fix
--fix
をつけると、eslint.config.mjs
に記述したルールに従って、自動的にコードを修正して保存をしてくれます。
今回の sample.js の場合、以下 4 つの項目を自動修正してくれました。
- インデントの修正
- ダブルクォートをシングルクォートに修正
- セミコロンの修正
- ブレースのスタイルの修正
diff --git a/sample.js b/sample.js
index fad3f9a..8b36e06 100644
--- a/sample.js
+++ b/sample.js
@@ -29,27 +29,26 @@ logMessage('message');
// 5. indent ルール
function greet(name) {
-return 'Hello, ' + name; // indent: インデントが不正
+ return 'Hello, ' + name; // indent: インデントが不正
}
-greet('Hello World')
+greet('Hello World');
// 6. quotes ルール
function sayHello() {
- const greeting = "Hello, World!"; // quotes: ダブルクォート使用
+ const greeting = 'Hello, World!'; // quotes: ダブルクォート使用
return greeting;
}
sayHello();
// 7. semi ルール
function getGreeting(name) {
- return 'Hello, ' + name // semi: セミコロンがない
+ return 'Hello, ' + name; // semi: セミコロンがない
}
getGreeting('World');
// 8. brace-style ルール
function showMessage(condition) {
- if (condition)
- { // brace-style: ブレースのスタイルが不正
+ if (condition) { // brace-style: ブレースのスタイルが不正
console.log('Condition is true');
}
}
@@ -75,7 +74,7 @@ function checkStatus(status) {
} else if (status === 'failure') {
return false;
} // consistent-return: 一貫性のない return
- // else { 'success' or 'failure' に該当しない場合にundefinedが返されてしまう
+ // else { 'success' or 'failure' に該当しない場合にundefinedが返されてしまう
// return null
// }
}
@@ -83,7 +82,7 @@ checkStatus('success');
// 12. no-var ルール
function displayMessage() {
- var message = 'Hello!'; // `var` が使用されている
+ const message = 'Hello!'; // `var` が使用されている
console.log(message);
}
displayMessage();
(END)
eslint の除外
以下のようにコメントを追加する事で、eslintの解析を除外する事ができます。
eslint-disable-line <ルール名>
eslint-disable <ルール名>
例の中で、変数 example_value がスネークケースでの記述になっており、camelcase
のルールが適用される事でエラーになりますが、コメントを追加することでeslintの解析から除外されます。
特定行の除外
特定の行だけ ESLint のルールを無視したい場合、次のように記述します。
const example_value = 'some-value'; // eslint-disable-line camelcase
特定ブロックの除外
複数行にわたってルールを無視したい場合、disable
とenavle
で囲って記述することで、ブロック内で指定したルールが無視されます。
/* eslint-disable camelcase */
const example_value = 'some-value';
const another_value = 'another-value';
/* eslint-enable camelcase */
特定ファイルの除外
ファイル全体で特定のルールを無効にしたい場合、次のようにファイルの冒頭にコメントを追加します。
/* eslint-disable camelcase */
const example_value = 'some-value';
const another_value = 'another-value';
最後に
eslint に関してはほぼ知識 0 からスタートしましたが、こうして試しながらまとめていくと基本的な利用方法は理解できたように思います。
そして、単純なミスでコードが動かないっという事が、圧倒的に少なくできると思うので、eslint を使わないという選択肢はなくなりました。
早速、実際野プロジェクトにも早速導入してみようと思います。
また、Prettierと強豪する部分もありますが、役割を分担して導入することでより一貫性を保ったスタイルになりそうなので、
今後Prettierについても学んで行こうと思います。
参考
Discussion