ESlint で import を自動ソートする
import が増えてくると、その順序が気になってきます。
外部ライブラリからのインポートは上にあって欲しいし、react
からのインポートはさらに上に固定したくなりませんか?
ESlint のeslint-plugin-import
というプラグインを使えば簡単にソートできます。
使うのはeslint-plugin-import
のimport/order
というルールです。
設定も色々あって、ある程度の自由度で順序を決めることもできます。このルールは fixable なのでeslint --fix
コマンドで自動ソートが可能です。
公式の解説もあるのですが分かりにくい個所や誤っている個所もあるためこの記事を作成しました。
ソートした例
早速eslint-plugin-import
のimport/order
を使ってソートした例です。
上が下のようにきれいになります。
ソート後はreact
からのインポートが最上部あって、次にその他の外部ライブラリ、エイリアスからのインポート(@src/**
)、親ディレクトリからのインポートとなっています。
これらの順序やエイリアスも自分の環境や好みによって自由に設定可能です。
最後に typescript の型インポートが別に分かれているのは別プラグインとの組み合わせで実現しています。
詳細な設定方法は下で解説します。
ソート前
import { TextField, Box, BoxProps } from '@mui/material';
import { LoadingButton } from '@mui/lab';
import { useAddAppNotification } from '@src/common/hooks/useAppNotifications';
import { SubmitHandler, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { useEffect } from 'react';
import { useSignIn } from '../hooks/useSignIn';
ソート後
import { useEffect } from 'react';
import { LoadingButton } from '@mui/lab';
import { TextField, Box } from '@mui/material';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { useAddAppNotification } from '@src/common/hooks/useAppNotifications';
import { useSignIn } from '../hooks/useSignIn';
import type { BoxProps } from '@mui/material';
import type { SubmitHandler } from 'react-hook-form';
設定の方法
上記のソートは下記のような設定で実現しています。
ソートの順序は ESlint ルールのオプションで設定します。
{
rules:{
'import/order': [
'error',
{
groups: ['builtin', 'external', 'parent', 'sibling', 'index', 'object', 'type'],
pathGroups: [
{
pattern: '{react,react-dom/**,react-router-dom}',
group: 'builtin',
position: 'before',
},
{
pattern: '@src/**',
group: 'parent',
position: 'before',
},
],
pathGroupsExcludedImportTypes: ['builtin'],
alphabetize: {
order: 'asc',
},
'newlines-between': 'always',
},
],
'@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports' }],
// その他のルール
}
}
設定の解説
上記の設定例を使って各項目ごとの意味と設定方法を解説します。
より詳細が知りたい場合は以下の github の解説ページを見てください。
groups
グループごとのインポート順を設定できます。グループとは「外部ライブラリ」や「親ディレクトリ」などの既定の分類です。以下が全てのグループの名称です。名前でだいたい想像できますが詳細な説明は github で確認できます。
['builtin', 'external', 'internal', 'unknown', 'parent', 'sibling', 'index', 'object', 'type']
pathGroups
上記groups
に加え独自のグループを path を基準に自分で作り任意の場所に配置することができます。これによってかなり自由度の高いソートが可能になっています。
例えば下記は@src/**
ではじまるパスからのインポートをグループにして、parent
グループの前に持ってくるという設定です。
新しく作ったグループはgroup
とposition
を使って配置個所を指定します。
group
には位置の基準となる既定のグループ名を指定します。position
にafter
かbefore
を設定すれば新規グループは基準となるグループの後か前に配置されます。position
を選択しないと、新規グループは基準となるグループに含まれます。
@src/**
は私が別途設定しているエイリアスなのですが、設定しないと@
からはじまるパスは外部ライブラリとして処理されてしまいます。そのためこの設定が必要なのです。
{
pattern: '@src/**',
group: 'parent',
position: 'before',
}
また、以下の設定ではreact
,react-dom/**
,react-router-dom
からのインポートを 1 つのグループにしてbuiltin
よりも前に配置するよう設定しています。
ここでpattern
で{}
や**
を使っています。pattern
はminimatch
で解釈されるのでminimatch
で使えるパターンが使用できます。
{
pattern: '{react,react-dom/**,react-router-dom}',
group: 'builtin',
position: 'before',
}
pathGroupsExcludedImportTypes
pathGroups
の pattern の判定が影響されないグループを設定することができます。
デフォルト値は['builtin', 'external', 'object']
です。
react
関連のインポートはexternal
なので、pathGroupsExcludedImportTypes
がデフォルト値のままだとpathGroups
が適用されません。
pathGroupsExcludedImportTypes
を['builtin', 'object']
にすることで上記で紹介したpathGroups
が効果を発揮します。
ちなみに github の docs では"pathGroupsExcludedImportTypes": ["react"]
のような例がありますが、これは使い方を間違っています。docs を修正するプルリクエストも出ているようです。
alphabetize
これはグループ内の順序づけの方法です。グループ内は順序つけしないか、アルファベット昇順、降順が選べます。
newlines-between
グループ間のスペースの設定です。今回の設定では必ずスペースを配置しています。
型のインポートを分ける
typescript の型のインポートをimport type ...
のように Type-only imports の形式で分けるには別の ESlint ルールが必要です。
上記のルール設定例の最後にある@typescript-eslint/consistent-type-imports
がそれです。
これで型インポートをimport type ...
の形式で分離され、import/order
でソートが可能になります。
Discussion