LCL Engineers' Blog

バス比較なび・格安移動・バスとりっぷを運営する LCLの開発者ブログ

ESLintのバージョンをv6.8.0からv8.4.1に上げる

この記事はLCL Advent Calendar 2021 - 17日目です。

qiita.com

フロントエンドエンジニアのsatoshioです。

先日弊社が提供しているバスツアー検索サービスでESLintおよびPrettierのバージョンアップ対応を行ったので、今回は対応の流れやそこで遭遇したエラーとその解決方法についてまとめます。

日帰り・宿泊バスツアーの人気格安プラン検索【バス比較なび】

目標

  • ESLintを最新のバージョンにアップグレードする
  • Prettierを最新のバージョンにアップグレードする

準備

現状の確認

対応開始時点でのESLintの最新バージョンはv8.4.1Prettierの最新バージョンはv2.5.1のようです。

一方で、バスツアー検索サービスで使用しているバージョンはというと...

{
  "dependencies": {
    "nuxt": "2.15.8",
    ...
  }
  "devDependencies": {
    "eslint": "6.8.0",
    "prettier": "2.3.0",
    ...
  }
}

PrettierはともかくESLintは最新とかなり離れてしまっています...。

リリースノートの確認

ESLint 

Releases

v6.8.0-v8.4.1間の更新内容を確認していきます。当たり前ですがそこそこ量がありますね...。メジャーバージョンが2つ変わっているのでBreaking changesもそれなりにあります。

v7.0.0の時点でNode.js v8v8.0.0の時点でNode.js v10, v13, v15のサポートが終了していますが、バスツアー検索サービスのNode.jsは既にLTSまで上げてあるのでここは問題なさそうです。

詳細は省略しますが、他のBreaking changesについても影響がないことを確認しました。

Prettier

Releases

v2.3.0-v2.5.1間の更新内容を確認していきます。ほとんどは既存機能のFixとImproveのようです。

Collapse HTML class attributes onto one line (#11827 by @jlongster)あたりの修正(厳密にはRevertですが)は良さそうですね。Tailwind CSSのように大量のクラスが付与される場合のフォーマットは難しそうです。

jsxBracketSameLineが非推奨になり新たにbracketSameLineが追加されましたが、確認したところ今回は関係なさそうです。

対応

ESLint

リリースノートも確認したので、とりあえずバージョンを上げてみます。

npm install eslint@latest —save-dev
npm run dev

Module build failed (from ./node_modules/eslint-loader/dist/cjs.js):  
TypeError: Cannot read properties of undefined (reading 'getFormatter')

エラーが発生するようになりました。バージョンアップにはつきものですね。リリースノートを確認しているとはいえメジャーバージョンを2つもあげているのにすんなり動いたらそれはそれで怖いのでかえって安心します。

eslint-loader周り

エラー内容を読む限りどうやらeslint-loader絡みのようなのでとりあえずeslint-loader公式を確認しにいったところ、なんとeslint-loaderは2020年9月にDEPRECATEDされていました。「変わりにeslint-webpack-pluginを使用してね」とのことなので、そのように変更します。

ただ、色々調べたところ@nuxtjs/eslint-module(eslint-webpack-pluginを内包している)を使用するのが良さそうだったので、今回はそちらを使用するようにしました。リリースノートからも、v3.0.0でeslint-loaderからeslint-webpack-pluginを使用するように変更されていることがわかります。

npm uninstall eslint-loader
npm install @nuxtjs/eslint-module --save-dev

nuxt.config.jsを修正します。合わせてbuildに記載されているeslint-loader用のホットリロードの設定も削除します。

export default {
  build: {
-  extend(config, ctx) {
-    if (ctx.isDev && ctx.isClient) {
-      config.module.rules.push({
-        enforce: 'pre',
-        test: /\.(js|vue)$/,
-        loader: 'eslint-loader',
-        exclude: /(node_modules)/,
-        options: {
-          emitError: true,
-          emitWarning: true,
-          fix: true
-        }
-      })
-    }
-  }
  },
+ buildModules: [
+   '@nuxtjs/eslint-module'
+ ]
}

※ 余談: Rule can only have one resource source (provided resource and test + include + exclude) エラーが発生した場合

今回は@nuxtjs/eslint-moduleをinstallしましたが、@nuxtjs/eslint-moduleではなくeslint-webpack-pluginをinstallし、かつinstall済みのwebpackのバージョンがv5である場合、上記のエラーに遭遇する場合があります。

このエラーの原因は「eslint-webpack-pluginのバージョンとinstallされているwebpackのバージョンが一致していない」ことが考えられます。EslintWebpackPlugin

This is eslint-webpack-plugin 3.0 which works only with webpack 5. For the webpack 4, see the 2.x branch.

と記載されている通り、webpackがv5の場合はeslint-webpack-pluginはv3、webpackがv4の場合はeslint-webpack-pluginはv2を使用する必要があります。

と言いつつ、Nuxt.js内で使用されているwebpackのバージョンはv4(nuxt@2.15.8ではwebpack@4.46.0でした)なので、eslint-webpack-pluginもv2でinstallしないとエラーが発生する、といった感じです。

一応eslint-webpack-pluginをv2でinstallすれば解決できるのですが、新規Nuxt.jsプロジェクトをセットアップする際「ESLintを導入する」を選択した時にinstallされるのは@nuxtjs/eslint-moduleなので、そちらの設定の方が無難なのかなと思います。

babel-eslint周り

さて、これでエラーは解消されたはずなので再び実行してみます。

npm run dev

error  Parsing error: require() of ES Module /foo/bar/node_modules/eslint/node_modules/eslint-scope/lib/definition.js from /foo/bar/node_modules/babel-eslint/lib/require-from-eslint.js not supported.
Instead change the require of definition.js in /foo/bar/node_modules/babel-eslint/lib/require-from-eslint.js to a dynamic import() which is available in all CommonJS modules

別のエラーにたどり着きました。

エラー内容を読む限りどうやらbabel-eslint絡みのようなのでとりあえずbabel-eslint公式を確認しにいったところ、なんとbabel-eslintは2020年3月にDEPRECATEDされていました。「変わりに@babel/eslint-parserを使用してね」とのことなので、そのように変更します。このあたりを読むと@babel/eslint-parserがESLint v8に対応したことなんかも書いてありますね。

npm uninstall babel-eslint
npm install @babel/core @babel/eslint-parser --save-dev

.eslintrc.jsも修正します。

{
  ...
  "parserOptions": {
-    "parser": "babel-eslint",
+    "parser": "@babel/eslint-parser",
+    "requireConfigFile": false
  },
  ...
}

再び実行したところ、エラーが発生することなくNuxt.jsプロジェクトが立ち上がりました。試しに適当に全角スペースを挿入して保存してみます。

error  Irregular whitespace not allowed  no-irregular-whitespace

動作していそうですね。

Prettier

Prettierに関してはマイナーバージョンアップなのでESLintと比較すると少しだけ気が楽です。とりあえずバージョンを上げます。

npm install prettier@latest

動作も問題なさそうですが、少し調べたところESLint + Prettierの推奨設定が変わっていたので対応しておきます。こちらのサイトがわかりやすかったです。

要点をまとめると、

  • eslint-plugin-prettierは非推奨になった
  • eslint-config-prettierで競合ルールでoffにした後、prettier && eslintのようにチェックするようにする

という変更になります。バスツアー検索サービスでもeslint-plugin-prettierを使用していたので、忘れないうちにuninstallしておきます。

npm uninstall eslint-plugin-prettier

また、競合ルールをoffにする記述についてですがeslint-config-prettie v8.0.0から簡単になったようなので 、合わせて確認しておきます。

{
  extends: [
    ...
    'prettier' // 末尾に記述する v8.0.0からは 'prettier'のみでOK
  ],
  ...
}

あとは対応前後でデザインや動作に差異が発生していないかを別途確認し、対応完了です。

まとめ

今は便利な時代なので少し探せば同じ問題に遭遇した誰かしらが残した解決方法にたどり着ける時も多いのですが、仕様や推奨/非推奨の変更で少し前の対応方法が最適解にならない、それだけならまだしも適用すらできないことも多々あり、今回はその点で少々苦労したのでドキュメントを残すことにしました。似た問題を抱えた方の何かしらの役に立てば幸いです。

バージョンアップ対応はこまめに行うようにしましょう。

採用情報

フロントエンドチームでは、より良いサービスを提供していくために新しい仲間を募集しています。

カジュアルに会話できる機会もご用意できますので、もし興味がある方は気軽にご連絡ください。

www.lclco.com