PLAY DEVELOPERS BLOG

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

ESLintを導入して独自ルールを作成してみた

こんにちは。ソリューション事業部の樋口です。

最近私が担当している案件に、ESLintを導入する機会があったのでその際の手順を記載します。 同じ様な境遇の方の助けになれば幸いです。

ESLintとは何か?

JavaScript/TypeScriptのための静的検証ツールです。 プラグインで設定したルールに従って、ソースコードの問題点を指摘、場合によっては修正まで行ってくれます。 バグの発見と共に、プロジェクト内のコーディングルールの統一の手助けにもなります。

なぜESLintを導入したのか?

主な理由はコードレビューにかかるコストを下げるためです。 私の参画しているプロジェクトで採用しているJavaScriptでは、後々確認すると明らかなバグであってもそのままビルドできてしまい、実際にコードが実行されて初めてバグに気がつくことが多々あります。(私はありました) そのため、従来のコードレビューでは変数に未定義のものがないか、typoがないかなど、そもそも言語として正しい書き方をしているかなどの、単純な不具合がないかの確認に多くの時間が割かれていました。 前述したような単純な作業は機械に任せて、他作業に時間を充てられるようにしたいという思いがありました。

導入手順

今回導入したESLintのバージョンは以下の通りです。

  • ESLint 8.49.0

インストール

開発で使用しているパッケージマネージャーを使ってインストールしてください。今回はyarnを使用します。 開発時にのみ利用する想定のため、オプションに -D を指定します。

yarn add -D eslint

※ ESLintは約2週間ごとに新しいバージョンがリリースされているようなので、インストール時点の最新バージョンは異なる可能性が高いです。 開発環境に適したバージョンを指定するようにしてください。

設定ファイルの作成

package.json内に設定を記載することもできますが、今回は別で設定ファイルを作成します。

yarn eslint --init

上記コマンドから、簡単に設定ファイルの雛形が作成できます。 開発環境に関して複数質問されるので、適当なものを選択してください。

ルールの選定

設定ファイルができたので、早速ESLintを動かしていきます。 ひとまずは何も考えずに、下記コマンドを入力してみます。

yarn run eslint . 

結果。。。

はい。すごい数のエラーが出ました。 これがプロジェクトの途中からESLintを導入する一番辛いところではありますが、ここで諦める訳にはいかないため、まずは最低限のルールに絞って導入します。どのルールを導入するかは、チームメンバーと決めるのが良いです。 現状の設定ファイルの内容を抜粋するとこんな感じです。

.eslintrc.js

module.exports = {
  ...
  extends: ['eslint:recommended', 'plugin:react/recommended'],
  plugins: ['react'],
  rules: {},
}

extendsとpluginsの違いについての詳細は省きますが、 簡単に説明すると、extendsではShareable Configs(よしなに採用ルールを選択・設定している設定ファイル)、pluginsではルールセットを指定します。extendsでShareable Configsを指定して、不要なルール設定は上書きするというのが王道かと思いますが、今回はルールへの理解を深める意味も込めて、extendsで指定せずに、rulesを全てこちらで指定することにしました。

最終的にルールは10個ほどに絞りました。下記一部抜粋

  • no-undef ─ 宣言されていない値を参照させないルール
  • no-const-assign ─ const宣言した変数への再格納を禁止するルール

ルールの設定をしなおしたところで、もう一度eslintコマンドを実行します。

yarn run eslint . 

結果は、、、

大分減りました。これならなんとかなりそうなので後はひたすら修正をして、、

完了です!

独自ルール

ESLintを運用していく上で、ほとんどのルールはすでに誰かが作成して公開されているのですが、まれに独自のルールを作成したい場合が出てくる可能性があります。 最後に簡単なルールを作成しながらその手順を紹介します。

ルールの作成

今回は、指定した変数名の使用を禁止するというルールを作成します。 変数名の指定に関しては、下記のように設定ファイルから行うことを想定しています。

ex) PLAYという変数名を使用した場合にエラーにする

.eslintrc.js

module.exports = {
  ...
  rules: {
    'no-specific-name': ['error', { names: ['PLAY'] }],
  },
}

ルールの構造に関しては公式ドキュメントに記載があるのでこちらを参考にします。 ESLintはソースコードをJavaScript ASTに変換し、それに対して操作を行います。(JavaScript ASTとはJavaScriptを解析し、木構造のJSONフォーマットで表現したものです。詳細は調べてみてください。)

ルールを作成する上で、現状どのようなJavaScript ASTが生成されているか知りたいことが多々あります。JS AST Explorerではソースコードを貼り付けると、即座にJavaScript ASTを生成してくれるのでルール作成の手助けになります。

出来上がったルールのコードがこちら

rules/no-specific-name.js

'use strict';

module.exports = {
  meta: {
    type: 'suggestion',
    docs: {
      description: 'Description of the rule',
    },
    fixable: 'code',
    schema: [
      {
        type: 'object',
        properties: {
          names: {
            type: 'array',
            items: {
              type: 'string',
            },
          },
        },
        additionalProperties: false,
      },
    ],
  },
  create: function(context) {
    const [options] = context.options || [{}];
    const names = options.names || [];
    return {
      VariableDeclarator: function(node) {
        if (
          node.id &&
          names.some(function(name) {
            return name === node.id.name;
          })
        ) {
          context.report({ node, message: `${node.id.name} is not allowed for variable name` });
        }
      },
    };
  },
};

※ ESLintはルールが必要としているノードだけ、ルールに渡してくれます。 今回の場合はVariableDeclarator をキーとしているので変数の宣言時です。

テストの作成

ルールを作成したら、意図通りにルールが動くのかのテストも必要です。 今回はESLintのRuleTesterとmochaを使用してテストコードを実装、実行します。バージョンは以下の通りです。

  • mocha 10.2.0

tests/no-specific-name.js

'use strict';

const rule = require('../rules/no-specific-name');

const RuleTester = require('eslint').RuleTester;
const ruleTester = new RuleTester();

const name = 'PLAY';
// optionがないルールの場合は不要
const options = [{ names: [name, 'play'] }];

const valid = [
  {
    code: 'var Play = "PLAY";',
    options,
  },
  {
    code: 'var PLAY_ = "PLAY";',
    options,
  },
];

const invalid = [
  {
    code: 'var PLAY = "hoge";',
    options,
    errors: [{ message: `${name} is not allowed for variable name`, type: 'VariableDeclarator' }],
  },
];

ruleTester.run('no-specific-name', rule, { valid, invalid });

それっぽいテストコードが書けたのでテストを実行していきます。

$ yarn mocha eslint/tests/no-specific-name.js
yarn run v1.22.19

  no-specific-name
    valid
      ✔ var Play = "PLAY";
      ✔ var PLAY_ = "PLAY";
    invalid
      ✔ var PLAY = "hoge";


  3 passing (39ms)

✨  Done in 0.74s.

無事テストが通りました! 作成したルールはpluginとして公開して利用するか、またはプロジェクト内で完結するルールとして利用できます。

ルールの作成としてはこれにて完了です。

まとめ

この記事では、ESLintの導入手順と独自ルールの作成方法について解説しました。

ESLintは健全なJavaScript開発において不可欠なツールであり、コードの品質向上や一貫性の確保に大きく寄与します。独自ルールの作成により、プロジェクトの特有のニーズや規約に合わせた柔軟な静的解析が可能となります。

プロジェクト全体で一貫性のあるコーディングスタイルを確立することで、より効果的で持続可能なJavaScript開発が実現できるでしょう。是非、プロジェクトに導入し、開発体制の向上に寄与してみてください。

参考

eslint.org

engineering.mercari.com

techblog.yahoo.co.jp