🎉

Next.jsに専用のESLintが追加された!

2021/06/17に公開

Next.js11がついに発表されましたね。

next/scriptNext.js Liveなど、興味深い機能が色々ですが、自分が地味に嬉しかったのはNext.js専用のESLint設定がデフォルトでサポートされたことです。

create-next-appでESLint設定済みのNext.jsプロジェクトが作成できる

ReactやNext.jsのプロジェクトを立ち上げる際、結構面倒くさい難しいのがESLintの設定です。
.eslintrcファイルの記述とか、extendsの記述順によって優先されるルールとかも変わってくるので、慣れないうちはなかなか難しい作業でしょう。(自分はいまだに試行錯誤してます…)

しかし、今ではcreate-next-appを使うと、専用のESLintが設定済みのNext.jsプロジェクトを作成してくれます。

実際にコマンドを実行した結果を見ていきましょう。

$ npx create-next-app app --typescript # `app`は任意のプロジェクト名でOK
Creating a new Next.js app in /Users/johnnydoe/Documents/app

Using npm.

Installing dependencies:
- react
- react-dom
- next


added 268 packages, and audited 269 packages in 9s

44 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Installing devDependencies:
- eslint
- eslint-config-next # ←Next.js用のESLint設定
- typescript
- @types/react


added 217 packages, and audited 486 packages in 10s

78 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Initialized a git repository.

Success! Created app at /Users/johnnydoe/Documents/app
Inside that directory, you can run several commands:

  npm run dev
    Starts the development server.

  npm run build
    Builds the app for production.

  npm start
    Runs the built app in production mode.

We suggest that you begin by typing:

  cd app
  npm run dev

メッセージを見ると、この時点でESLintとNext.js専用のeslint-config-nextをインストールしてくれているのがわかります。

さらに作成されたプロジェクトを見ると、すでに.eslintrcファイルが作成されています。

package.jsonscriptsにも"link": "next lint"というコマンドが新規で追加されています。

package.json
{
  "name": "app",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "next": "11.0.0",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  },
  "devDependencies": {
    "@types/react": "17.0.11",
    "eslint": "7.28.0",
    "eslint-config-next": "11.0.0",
    "typescript": "4.3.3"
  }
}

このnext lintを実行すると、以下の処理が実行されるようです。

  1. (まだプロジェクトにインストールされていない場合、)eslinteslint-config-nextをインストールするよう促すメッセージを表示。
  2. (まだプロジェクト内に作成されてない場合、).eslintrcを作成。
  3. プロジェクト内のコードにwarningerrorが無いか、設定されているESLintルールに沿って検査。

1.と2.については、既存のNext.js10のプロジェクトをNext.js11へアップグレードした場合などに便利ですね。

eslint-config-nextはどんな設定になっているのか

eslint-config-nextのソースコードを見てみると、以下のような設定になってました。

eslint-config-next/index.js
module.exports = {
  extends: [
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:@next/next/recommended',
  ],
  plugins: ['import', 'react', 'jsx-a11y'],
  rules: {
    'import/no-anonymous-default-export': 'warn',
    'react/react-in-jsx-scope': 'off',
    'react/prop-types': 'off',
    'jsx-a11y/alt-text': [
      'warn',
      {
        elements: ['img'],
        img: ['Image'],
      },
    ],
  },
  **省略**
}

reactreact-hooksimportjsx-a11yなど、ReactやNext.jsのプロジェクトに導入されることの多いプラグインは一通り入ってますね。@next/nextはNext.js独自のルールのようです。

どんなルールがあるのか

まだ全部検証できているわけではないですが、デフォルトの状態で有効になっているNext.js独自のルールをいくつかピックアップしてみます。

Do not use the HTML <a> tag to navigate to ${hrefPath}. Use Link from 'next/link' instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages.

サイト内リンクを<a>タグで貼ろうとすると、next/linkからインポートした<Link>コンポーネントを使うように警告されます。

no-image-element

Do not use <img>. Use Image from 'next/image' instead. See https://nextjs.org/docs/messages/no-img-element.

画像を貼る際に<img>タグを使おうとすると、next/Imageからインポートした<Image>コンポーネントを使うよう警告されます。

no-sync-script

External synchronous scripts are forbidden. See: https://nextjs.org/docs/messages/no-sync-scripts.

<script>タグで、なにかしらのスクリプトを読み込もうとすると、「(Webサイトのパフォーマンスに影響を与える可能性のある)同期スクリプトが使用されました」とエラーが出ます。代わりにnext/scriptからインポートした<Script>コンポーネントを使用すると、そのスクリプトが必要となったタイミングで読み込んでくれるようです。

終わりに

公式で用意されているESLintルールは、総じてNext.jsの機能を最大限に発揮させるために制定されている感じですね。

恐らく実務で使用する上では、これらのデフォルトで設定されているルールを微調整する必要はあるでしょうが、これまでは一から自分たちで設定する必要があったことを考えれば、こうして公式が最低限必要なルールを制定してくれるのは、とても助かりますね。

修正とお詫び

本記事において、当初「Next.jsの<Link>コンポーネントとjsx-a11y/achor-is-validを併用した際に起こるエラー」について、さも公式ESLintが対応しているかのように紹介していましたが、これは誤りでした。

もう一度、eslint-config-nextのソースコードをご覧ください。

eslint-config-next/index.js
module.exports = {
  extends: [
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:@next/next/recommended',
  ],
  plugins: ['import', 'react', 'jsx-a11y'],
  rules: {
    'import/no-anonymous-default-export': 'warn',
    'react/react-in-jsx-scope': 'off',
    'react/prop-types': 'off',
    'jsx-a11y/alt-text': [
      'warn',
      {
        elements: ['img'],
        img: ['Image'],
      },
    ],
  },
  **省略**
}

ご覧の通り、jsx-a11y/alt-textしか有効になってません。

つまりNext.jsのデフォルトのESLint設定ではそもそもjsx-a11y/anchor-is-validのエラーなど起こりようが無いと言うことですね…

当初の内容をそのままにしておくと間違った認識を広めてしまいかねないので、<Link>コンポーネントとjsx-a11y/anchor-is-validを併用する際に起こる問題」について言及した部分に関しては、すべて削除しました。

私の思い込みと確認不足によって誤った情報を載せてしまい、大変申し訳ありませんでした。🙇‍♂️

Discussion