Madogiwa Blog

主に技術系の学習メモに使っていきます。

TypeScript/Vue.js/Prettierを使った環境でESLintの新しい設定 Flat Configに移行した📝

2024/04/06 ESLint v9がリリースされました🎉

eslint.org

Flat config is now the default and has some changesとあるように、 v9からは今までとは違うFlat Configという設定方法がデフォルトになります。(ESLINT_USE_FLAT_CONFIGfalseを指定することで今まで通りの設定も使い続けることは可能)

eslint.org

今回は個人で開発しているVue.jsとTypeScriptとPrettierを利用しているサービスでFlat Configに移行してみたので、やったこととかをメモ📝

公式のmigrationガイドもあるので、こちらもご参照ください。

eslint.org

終結

元のESLintのconfigファイル .eslintrc.cjs

module.exports = {
  env: {
    node: true,
    browser: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:vue/vue3-recommended",
    "plugin:vue-scoped-css/base",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
  ],
  root: true,
  plugins: ["@typescript-eslint", "prettier"],
  parser: "vue-eslint-parser",
  parserOptions: {
    parser: "@typescript-eslint/parser",
    ecmaVersion: 2020,
    sourceType: "module",
    extraFileExtensions: [".vue"],
    project: "./tsconfig.json",
  },
  rules: {
    "prettier/prettier": "error",
    "no-console": "warn",
    "@typescript-eslint/no-unused-vars": [
      "warn",
      {
        argsIgnorePattern: "^_",
        varsIgnorePattern: "^_",
        caughtErrorsIgnorePattern: "^_",
      },
    ],
  },
  overrides: [
    {
      files: ["*.vue"],
      rules: {
        "vue/first-attribute-linebreak": "off",
        "vue/max-attributes-per-line": "off",
        "vue/singleline-html-element-content-newline": "off",
        "vue/html-self-closing": "off",
        "vue/max-lines-per-block": [
          "error",
          {
            style: 150,
            template: 200,
            script: 150,
            skipBlankLines: true,
          },
        ],
        "vue-scoped-css/enforce-style-type": ["error", { allows: ["scoped"] }],
        "@typescript-eslint/no-redundant-type-constituents": "off",
        "@typescript-eslint/no-unsafe-assignment": "off",
      },
    },
  ],
};

Flat Configに移行後 eslint.config.js

import js from "@eslint/js";
import ts from "typescript-eslint";
import vue from "eslint-plugin-vue";
import vueParser from "vue-eslint-parser";
import vueCss from "eslint-plugin-vue-scoped-css";
import prettierConfig from "eslint-plugin-prettier/recommended";
import globals from "globals";

export default [
  { ignores: [/* ignores */] },
  js.configs.recommended,
  ...ts.configs.recommendedTypeChecked,
  ...vue.configs["flat/recommended"],
  ...vueCss.configs["flat/base"],
  prettierConfig,
  {
    languageOptions: {
      parser: vueParser,
      parserOptions: {
        ecmaVersion: 2020,
        parser: ts.parser,
        extraFileExtensions: [".vue"],
        sourceType: "module",
        project: ["./tsconfig.json"],
      },
      globals: {
        ...globals.browser,
        ...globals.node,
      },
    },
  },
  {
    rules: {
      "prettier/prettier": "error",
      "no-console": "warn",
      "@typescript-eslint/no-unused-vars": [
        "warn",
        {
          argsIgnorePattern: "^_",
          varsIgnorePattern: "^_",
          caughtErrorsIgnorePattern: "^_",
        },
      ],
    },
  },
  {
    files: ["*.vue", "**/*.vue"],
    rules: {
      "vue/first-attribute-linebreak": "off",
      "vue/max-attributes-per-line": "off",
      "vue/singleline-html-element-content-newline": "off",
      "vue/html-self-closing": "off",
      "vue/max-lines-per-block": [
        "error",
        {
          style: 150,
          template: 200,
          script: 150,
          skipBlankLines: true,
        },
      ],
      "vue-scoped-css/enforce-style-type": ["error", { allows: ["scoped"] }],
      "@typescript-eslint/no-redundant-type-constituents": "off",
      "@typescript-eslint/no-unsafe-assignment": "off",
    },
  },
];

やったこと

.eslintignoreからFlat Config内のignoresに移行する

.eslintignoreは以下の通りignoresで指定するように変更になっています。

To ignore files with flat config, you can use the ignores property in a config object. https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files

以下のようにignoresプロパティに.eslintignoreの内容を文字列の配列に変換して指定するようにしました。

export default [
  { ignores: [ /* ignores files */ ] },

各種関連ライブラリの導入方法をFlat Configに対応したものに修正する

元々はextends等を使って導入していた各種ライブラリをFlat Config対応の導入方法が別途README等に記載されていたので、それに従って利用するように修正しました。

typescript-eslint.

  • ...tseslint.configs.recommended turns on our recommended config.

https://typescript-eslint.io/getting-started#step-2-configuration

eslint-plugin-vue

import pluginVue from 'eslint-plugin-vue'
export default [
  ...pluginVue.configs['flat/recommended'],

https://eslint.vuejs.org/user-guide/#configuration-eslint-config-js

eslint-plugin-prettier

const eslintPluginPrettierRecommended = require('eslint-plugin-prettier/recommended');
module.exports = [
  eslintPluginPrettierRecommended,
];

https://github.com/prettier/eslint-plugin-prettier?tab=readme-ov-file#configuration-new-eslintconfigjs

またFlat Configに対応してないライブラリがある場合には、従来のextendspluginsを使って利用することもできるようです。

github.com

global、parser周りの設定をlanguageOptionsに移行する

.vueファイルに対してTypeScript関連も含めて静的解析させるためにparser周りの設定以下を参照しlanguageOptionsに移行しました。

基本的にはlanguageOptionsの中にparserOptionsがあるので、以前のparservue-eslint-parserを使いつつparserOptionsparser@typescript-eslint/parserを使い、extraFileExtensionsも指定することができました。

  {
    languageOptions: {
      parser: vueParser,
      parserOptions: {
        ecmaVersion: 2020,
        parser: ts.parser,
        extraFileExtensions: [".vue"],
        sourceType: "module",
        project: ["./tsconfig.json"],
      },
      globals: {
        ...globals.browser,
        ...globals.node,
      },
    },
  },

また、envプロパティはlanguageOptions内のプロパティとしてglobalsを利用して定義するようになっているので対応しました。

In flat config files, the globals, and parserOptions are consolidated under the languageOptions key; the env property doesn’t exist https://eslint.org/docs/latest/use/configure/migration-guide#configuring-language-options

github.com

overridesを削除する

今まではglobベースでのルールの切り替えにはoverridesを利用していましたがFlat Configではデフォルトで機能が提供されているようなので

By default, flat config files support different glob pattern-based configs in exported array. You can include the glob pattern in a config object’s files property. https://eslint.org/docs/latest/use/configure/migration-guide#configuring-language-options

以下のように、overridesを利用せずにそのまま書くことができます。

export default [
  {
    files: ["*.vue", "**/*.vue"],
    rules: { /* overrides rules */ }

実行オプションの--extは削除されたのでglobでの指定に移行する

元々は以下のような形で拡張子を絞って実行していたのですが、

$ eslint app/javascript spec/javascript --ext .vue,.js,.ts

以下の通りFlat Configではサポートされていないのでglobベースの指定に修正しました。

The following CLI flags are no longer supported with the flat config file format:

  • --ext

https://eslint.org/docs/latest/use/configure/migration-guide#cli-flag-changes

$ eslint 'app/javascript/**/*.{js,ts,vue}' 'spec/javascript/**/*.{js,ts,vue}'

おわりに

Flat Confg最初はあまり分かっておらず従来の方が読みやすいような?とか思ってたんですが、理解できるとコード量も少なくスッキリ書けそうなのと、自然なJavaScriptに近い形になっており分割とか管理もしやすそう📝✨

参考

zenn.dev

zenn.dev