ESLint Flat Config に移行し、ついでに Shopify の shareable config を導入した
趣味開発のプロジェクトで ESLint の設定を Flat Config に移行した
また従来は自作の shareable config を利用していたが、メンテが面倒になってきたので、適当な tech company のものにエイヤで乗り換えることにした
以下の2点を基準に選定し、@shopify/eslint-plugin
を採用した
- Flat Config に対応済みである
- JavaScript 向け / TypeScript 向け / ブラウザ向け / Node向けのように分割された config を提供している
移行作業
eslint.config.js
の型
/** @type {import('eslint').Linter.Config[]} */
const config = [
// ...
];
export default config;
import('eslint').Linter.FlatConfig[]
としている記事も見かけたが、deprecate されていたので今は Config
を使うようだ
Config[]
で提供されている shareable config の適用ファイルを絞りたい
@shopify/eslint-plugin
は以下のように config 配下に TypeScript 向けや Node 向け、React 向けといった設定値(型としては Config[]
) が生えており、それを spread syntax で展開して使用するインターフェイスとなっている
import shopifyEslintPlugin from "@shopify/eslint-plugin";
/** @type {import('eslint').Linter.Config[]} */
const config = [
...shopifyEslintPlugin.configs.typescript, // <- Config[]
...shopifyEslintPlugin.configs.react, // <- Config[]
];
ここで困るのが、プロジェクト内にブラウザ向けの React コード(configs.react
を適用させたい)と Node 向けコード(configs.node
を適用させたい)が混在するようなケース
上のような設定例で configs.react
を展開すると当然 Node 向けコードにも React 系の plugin や rules が有効になってしまい、ESLint がエラーで実行できなかったり不要な warnings が出たりする
どうにかして files
property と組み合わせて適用ファイルを絞りたいが、素朴に書いた以下のような設定は動かない
import shopifyEslintPlugin from "@shopify/eslint-plugin";
/** @type {import('eslint').Linter.Config[]} */
const config = [
// ...
{
files: [
// React files
],
// ↓ Config[] をここで spread しても動かない
...shopifyEslintPlugin.configs.react,
},
// ...
];
試行錯誤した結果、とりあえず以下のような設定で動かせた
import shopifyEslintPlugin from "@shopify/eslint-plugin";
/** @type {import('eslint').Linter.Config[]} */
const config = [
// ...
...shopifyPlugin.configs.react.map((c) => ({
...c,
files: [
// React files
],
})),
// ...
];
files
だけではなく ignores
などももちろん利用できる
ただこれは extend (とは呼ばないだろうが)した configs の持つ files
を完全に上書きしてしまっているので、場合によっては適用ファイルが不必要に広がることになる
config の定義を見て問題がないかよく確認した方が良いかもしれない
Flat Config 未対応の plugin
@eslint/eslintrc
の提供する FlatCompat
を利用する
pnpn add -D @eslint/eslintrc
import { fileURLToPath } from "node:url";
import { FlatCompat } from "@eslint/eslintrc";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const compat = new FlatCompat({
baseDirectory: __dirname,
});
const config = [
...compat.plugins("foobar"), // 従来 `plugins: string[]` に書いていた識別子
// ...
];
その他
Flat Config 導入前後で設定値に変化がないことを確認するためのツールを開発している方もいるようだ
今回は設定値を変化させないことをハナから目指していなかったが、一定以上の規模のプロジェクトではかなり役に立ちそう
Discussion