かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

React + TypeScript import 順をキレイにしたい

React のプロジェクトで import の並び順を揃えて見通しを良くしたい

前提

create-react-app --template typescript で作成したプロジェクトに ESLint と Prettier を導入してある

  • "react-scripts": "^5.0.0"
  • "react": "^17.0.2"
  • "typescript": "~4.1.5"
  • "eslint": "^8.6.0"
  • "prettier": "2.5.1"

1. 使用してない import 自動削除する

eslint-plugin-unused-imports を使用する

$ npm i -D eslint-plugin-unused-imports

.eslintrc.json に設定を追加する

{
  "plugins": [
    "react",
    "@typescript-eslint",
+   "unused-imports"
  ],
  "rules": {
+   "@typescript-eslint/no-unused-vars": "off", // or "no-unused-vars"
+   "unused-imports/no-unused-imports": "error",
+   "unused-imports/no-unused-vars": [
+     "warn",
+     { "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" }
+   ],
  }
}
  • "@typescript-eslint/no-unused-vars" … unused-imports のルールとバッティングするので off にする
  • "unused-imports/no-unused-imports" … unused-imports の使用していない import に対するルール
  • "unused-imports/no-unused-vars" … unused-imports の no-unused-vars ルール
    • "vars": "all" … global スコープを含め全ての変数をチェックする
    • "varsIgnorePattern": "^_", … チェックしない変数を Regexp で指定できる。 _ で始まる変数が使用されてなくても OK にする
    • "args": "after-used" … 引数の使用してない変数に対するチェック。使用している変数が引数の最後の変数であれば、それより前の引数は使ってなくても OK
    • "argsIgnorePattern": "^_" … varsIgnorePattern の引数版。チェックしない引数を Regexp で指定できる。_ から始まる引数は使用のチェックを行わない

cf. no-unused-vars - Rules - ESLint - Pluggable JavaScript linter

2. import の並び順を揃える

eslint-plugin-import で import の順番を強制できる

$ npm i -D eslint-plugin-import

.eslintrc.json に設定を追加

{
  "plugins": [
    "react",
    "@typescript-eslint",
    "unused-imports",
+   "import"
  ],
  "rules": {
    // … 略
+   "import/order": []
  }
}

import の並び順のルール

.eslintrc.jsonimport/order ルール内に import の並び順のルールを記述する
GitHub にあるルールのドキュメント が参考になる

e.g.

{
  "rules": {
    "import/order": [
      "error",
      {
        // グループごとの並び順
        "groups": [
          "builtin",  // 1. fsや path などの node "builtin" のモジュール 
          "external",  // 2. npm install したパッケージ
          "internal", // 3. webpack などでパス設定したモジュール
          ["parent", "sibling"], // 4. 親階層と小階層のファイル
          "object",  // object"-imports
          "type",  // 型だけをインポートする type imports
          "index" // 同階層のファイル
        ],
        // グループごとに改行を入れる
        "newlines-between": "always", // "never" を指定すると改行なし
        // FIXME: ちょっとよく分かってない
        // This defines import types that are not handled by configured pathGroups. This is mostly needed when you want to handle path groups that look like external imports.
        "pathGroupsExcludedImportTypes": ["builtin"],
        // アルファベット順・大文字小文字を区別しない
        "alphabetize": { "order": "asc", "caseInsensitive": true },
        // パターンマッチしたものをグループにする
        // "newlines-between": "always" の場合は pathGroups  ごとに空行が入る
        "pathGroups": [
          // react 関連を external より前にする
          // "pathGroupsExcludedImportTypes": ["react"], にしてみたが `react`, `react-dom` などが別グループになってしまったので pattern で無理やり同じグループにした
          {
            "pattern": "react**",
            "group": "external",
            "position": "before"
          },
          // `@/app`, `@/features/`, `@/libs` の import をひとグループにして internal の前に
          {
            "pattern": "{@/app/**,@/features/**,@/libs/**}",
            "group": "internal",
            "position": "before"
          },
          // `@/components`, `@/pages` の import をグルーピング
          {
            "pattern": "{@/components/**,@/pages/**}",
            "group": "internal",
            "position": "before"
          },
          // CSS module を一番最後に
          {
            "pattern": "./**.module.css",
            "group": "index",
            "position": "after"
          }
        ]
      }
    ]
  }
}

ESLint でフォーマットするスクリプトを追加

未使用の import の削除も import の順番の強制も ESLint のルールなので eslint --fix で修正できる
コードフォーマットの prettier 合わせてフォーマットできるように npm-script を作成しておくと便利

package-json

{
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
+   "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
+   "lint:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'",
+   "format": "npm run lint:fix && prettier --write 'src/**/*.{js,jsx,ts,tsx}'",
    "eject": "react-scripts eject"
  }

👇 フォーマット

$ npm run format

ESLint が実行された後に prettier でフォーマットされていれば OK

VS Code の保存時にフォーマットする

コマンド叩き忘れがないように保存時に自動フォーマットするようにしておく

.vscode/settings.json

{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
}

おわり

ESLint 関連のルール ドキュメントの説明を見てもよくわからんのが結構あるので英語力…ってなる。
個人的にはどうなるのかのサンプルコードを載せていたほうが親切だよなって感じたので、自分がなにか公開する際はそうしようって思いました。

ESLint + Prettier の設定毎回毎回何度も作ってる気がするので、そろそろテンプレート化しておきたい。(作る度にパッケージのアップデートで指定方法が変わってたりするから毎回手直しすることにになってるけど…)


[参考]