Next.jsプロジェクトでTypeScriptのimportの並び順を指定する

JavaやKotlinを長く書いてきて、importの並び順、ソートはフォーマッターにお任せだった。

Next.jsをTypeScriptで書いているプロジェクトでも、Javaと同様、importの順序を統一したいと思い、設定したのでメモ。

環境

Next.js v12.1.5。パッケージマネージャーには Yarn v1.22.15を使用。

ESLintプラグインの導入

importの順序やソート順を変更するプラグインは複数あるが、よく使われている eslint-plugin-import は、Next.jsの公式ESLint設定である eslint-config-next含まれている

そのため、 create-next-app でプロジェクトを作成し、 .eslintrcnext/core-web-vitalsnextextends していれば、プラグインを明示的にインストールしなくても、importの順序の設定が可能。

ただ、ソート順の設定だけでなく、不要なimportの削除もしたいので、eslint-plugin-unused-imports を追加した。また、Prettierとの共存のため、 eslint-config-prettier も追加している。

yarn add -D eslint-config-prettier eslint-plugin-unused-imports

ちなみに、 eslint-plugin-import は、 eslint-config-react-appeslint-config-airbnb などにも含まれている模様。

.eslintrc の記述

以下、JSONCで例を記述。

import順の設定

import/order の記述方法は以下。

github.com

こちらの記事も参考になった。

qiita.com

基本的な並び順は groups で、パッケージ名などによるカスタマイズは pathGroups で行う。

react, nextが上に、CSSファイルは最下段に来るようにしている。

また、Amplifyを使用しているため、APIやgraphqlのimportは上に、Figma連携で作成されたUIコンポーネント(ui-components 配下)は下に来るようにし、Figma連携で作られたファイルはESLintの対象外とした。

{
  "extends": [
    "next/core-web-vitals",
    // eslint-config-prettier を有効化
    "prettier"
  ],
  "ignorePatterns": ["src/ui-components/**"],
  "rules": {
    // importの並び順設定
    "import/order": [
      "error",
      {
        "groups": [
          "builtin",
          "external",
          "internal",
          ["parent", "sibling"],
          "object",
          "type",
          "index"
        ],
        "pathGroups": [
          {
            "pattern": "react",
            "group": "external",
            "position": "before"
          },
          {
            "pattern": "next/**",
            "group": "external",
            "position": "before"
          },
          {
            "pattern": "API",
            "group": "internal",
            "position": "before"
          },
          {
            "pattern": "graphql/**",
            "group": "internal",
            "position": "before"
          },
          {
            "pattern": "ui-components/**",
            "group": "index",
            "position": "after"
          },
          {
            "pattern": "**\\.css",
            "group": "index",
            "position": "after"
          }
        ],
        "pathGroupsExcludedImportTypes": ["react", "next/**"],
        "newlines-between": "always",
        "alphabetize": { "order": "asc", "caseInsensitive": false }
      }
    ],
    // importをファイル先頭に記述
    "import/first": "error",
    // 最後のimportの後に空行を追加
    "import/newline-after-import": "error"
  }
}

ちなみに、importだけでなくrequireを用いてもこの設定は有効になる。Amplifyで追加したLambda関数内ではrequireを使っているが、そちらにも効いてくれた。

不要なimportの削除

前述の記事の通り、 pluginsrules の追加だけで有効となる。

{
  "plugins": ["unused-imports"],
  "rules": {
    "unused-imports/no-unused-imports": "error"
  }
}

波かっこ内のソート

これでimportの順序についてはソートできるようになったが、 import { b, a } from ...import { a, b } from ... にするような設定は、 eslint-plugin-import には存在しない。

調べると、ESLintの標準ルールセットである sort-imports に存在した。

eslint.org

ignoreMemberSort が対象だが、オプションの1つであり、これだけを有効化することはできない模様。

もう少し調べてみると、 eslint-plugin-import に同様の機能追加希望のissueが上がっており、そのコメントに共存させる設定方法が記載されていた。

github.com

シンプルに、 ignoreMemberSort 以外はすべてoffにすればいい。

{
  "rules": {
    "sort-imports": [
      "error",
      {
        "allowSeparatedGroups": true,
        "ignoreCase": true,
        "ignoreDeclarationSort": true,
        "ignoreMemberSort": false,
        "memberSyntaxSortOrder": ["none", "all", "multiple", "single"]
      }
    ],
    "import/order": [...]
  }
}

VSCodeの設定

エディタとしてVSCodeを使用しているので、ファイル保存時に自動保存をかけたい。

また、これまたJavaのように、不足しているimportがあれば、自動で追加させたい。

以下のように .vscode/settings.json を記述することで対応できた。

{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  // 保存時のアクション
  "editor.codeActionsOnSave": {
    // 不足しているimportの追加
    "source.addMissingImports": true,
    // ファイルのfix
    "source.fixAll": true
  }
}

どんな形式のファイルでもフォーマットしてほしいので、デフォルトのフォーマッターはPrettierにして、保存時にフォーマットするよう設定している。

ESLintの対象となるTypeScriptやJavaScriptファイルは、 editor.formatOnSave をoffにしておいたほうがいいかとも思ったが、 eslint-config-prettier を使っているおかげか、今のところ特に問題はなく使えている。

振り返り

importの順序はけっこう癖が出ると思う。

ファイルの修正のついでに人力ソートしてくれる人もいたりするが、それはそれで差分が増えてコードレビューの時に気になったりするので、機械的に統一できるようになってよかった。

eslint-config-next でルールを決めてくれれば、何もしなくていいので最高なんだけど、そこまではやらないか。本質的な部分ではないし。