フロントエンドエンジニアの渡辺です。 業務委託で働いてる身ですが記事書くことになりました。懐深い。
先日「ESLintのルール設定を全て確認して設定をする」ということをしました。 (ESLintはv4.0.0時点で240以上の設定項目があります。)
普段はルール設定が膨大なので必要な項目しか見ないのですが、 全てに目を通してみると得られた知見が多くあったので共有します。
設定方針
まず、ESLintの膨大なルール設定をどう設定するかを決めます。 やり方は大体3パターンに分類できます。
- 緩いルール設定(eslint:recommendedなど)を元に、設定を足して厳しくする。
- 厳しいルール設定(airbnbなど)を元に、設定を引いて緩くする。
- 既存のソースコードを解析し、ESLintの機能でルール設定を自動生成する。
今回は「入れたいルールに絞って設定したい」という思いがあり、 eslint:recommended を元にルール設定を付け足す方法にしました。
ESLintのルール内容
ESLintのルール244項目のうち、eslint:recommendedは47項目設定されています。
このeslint:recommendedを元に、21項目のルール設定を追加しました。
この追加したルール設定について、一部を紹介していきます。
ESLintのルールはジャンル分けされているので、ジャンルごとに見ていきます。
また --fix
オプションで自動修正できるものは(fixable)
をつけておきました。
1. Possible Errors
Possible Errorsは、構文やロジックのエラーに関連した設定です。
no-prototype-builtins
これは以下のコードでエラーになるのを防いでくれます。
const foo = Object.create(null); foo.hasOwnProperty('bar');
このコードがなぜエラーになるかというと Object.create(null)
で作ったオブジェクトはObject型にもかかわらず、Object.prototypeのメソッドを持たないからです。
そのため Uncaught TypeError: foo.hasOwnProperty is not a function
という例外を吐いて落ちてしまいます。
Object.prototypeのメソッドをインスタンスから呼び出すのは禁止し、 代わりにObject.prototypeをcallする書き方で対応します。
const foo = Object.create(null); Object.prototype.hasOwnProperty.call(foo, 'bar');
以前このエラーにハマったことがあったので、感激しながら秒速で設定しました。 ちなみに、そのときハマったコードというのがこちら↓ https://github.com/expressjs/cookie-parser/blob/1.4.3/index.js#L51
2. Best Practices
Best Practicesは、問題を回避するのに役立つ設定がまとめられています。
no-else-return (fixable)
elseブロック内でreturnしている場合、そのelseは省略できるのでエラーにします。
なお eslint --fix
で自動的に修正することができます。すごい……
// error if (x) { return y; } else { return z; }
// ok if (x) { return y; } return z;
経験的に「無駄にelse内でreturnしているとコードが複雑化しやすい」と 感じていて、ESLintでたまたま禁止できたので設定しました。
radix
parseInt()
を使うとき、第二引数を強制します。
ES5以前のparseIntでは8進数を自動検出するようになっており、
parseInt("071");
を実行すると 57
となってバグ原因になるのでエラーにします。
みなさんは知っていましたか?私は知りませんでした……
ただし、最近のブラウザであれば 71
になるので今は不要かもしれません。
3. Stylistic Issues
Stylistic Issuesでは、コードのスタイルに関連する設定がまとめられています。 「ただのスタイルでしょ?趣味のルール設定なのでは?」と思うかもしれませんが、 意外に重要な設定もあったので紹介したいと思います。
comma-dangle (fixable)
いわゆるケツカンマを強制します。 例えば、
{ bar: 0 }
を
{ bar: 0, baz: 1 }
のように変更してコミットすると baz: 1
しか意味的な差分がないのに、
bar: 0,
と baz: 1
の2行にコード差分が出てしまいます。
そうするとコードレビューしずらかったり、コンフリクトの原因にもなるので
ケツカンマ必須に設定しました。
eol-last (fixable)
ファイルの最後に必ず改行を入れるようにします。 これもgit差分を増やさないため設定しました。
max-depth
ブロックのネスト数によってエラーにしてくれます。 以下のコードはネスト数5です。こんなコード見たくありませんよね。
for (;;) { let val = () => (param) => { if (true) { if (true) { // ネスト4 if (true) { // ネスト5 } } } }; }
速攻でエラー設定にしました。 とはいえ設定は緩めで、4までネストOKにしています。 「3で警告して4以上はエラー」のような設定ができないので緩くしました。
max-nested-callbacks
コールバックのネスト数によってエラーにしてくれます。 以下のコードはネスト数4です。やはりこんなコード見たくない。
foo1(function() { foo2(function() { foo3(function() { // ネスト3 foo4(function() { // ネスト4 }); }); }); });
とはいえ、これも max-depth
と同じ理由で少し緩めの3に設定しています。
no-lonely-if (fixable)
以下のような無駄なifのネストをエラーにしてくれます。
これもeslint --fix
で自動修正が可能です。すごい……
// error if (foo) { // ... } else { if (bar) { // ... } }
// ok if (foo) { // ... } else if (bar) { // ... }
これも no-else-return
と同じで、前から禁止したいと思っていました。
こんなコードを書いてしまうときは追い詰められて頭がボケているときなので、
速攻でエラー設定にしました。
no-tabs
タブによるインデントは本当に嫌いなので禁止にしました。例えば
const foo = { bar: 0, x : 1, // xと:の間がタブ文字 };
のようなコードがあった場合、他の人の環境では表示崩れを起こすかもしれません。
const foo = { bar: 0, x : 1, };
こんな風に崩れたのを見た日には、喧嘩が起きても不思議ではありません。 そのため最初からエラーにしておくと平和が保たれます。
4. ECMAScript 6
ECMAScript 6は、ES2015以降の構文に関する設定がまとまっています。
prefer-const (fixable)
constで問題無いのにも関わらずletを使っているとエラーにしてくれます。 例えば、
let a = 3; console.log(a); return
わざわざletを使っているということは、どこかで再代入していると予測できるので、
再代入箇所がないか気をつける必要がでてしまいます。
これも eslint --fix
で自動修正できて便利なので、エラーに設定しました。
prefer-rest-params
これは、暗黙の変数であるargumentsの使用を禁止します。 暗黙の変数自体使うのを避けたいですし、ES2015であればrest parametersで代用できますし、argumentsはArray.prototypeのメソッドを使えないので少し不便です。 わざわざargumentsを使うメリットが見当たらないのでエラーにしました。
// error function foo() { console.log(arguments); } function bar(a, b) { console.log(a, b, arguments); }
// OK function foo(...args) { console.log(args); } function bar(...args) { const {a, b} = args; console.log(a, b, args); }
設定しなかったルール
設定しなかったものや、検討に悩んだものもあるので紹介します。
セミコロンなし
セミコロン有り派が多いのでセミコロン必須で設定しました。 セミコロンがないと意図しないバグやエラーの原因になるからです。 ただ、ESLintを見ていくと、意図しないセミコロン抜けがある場合にエラーを出すルールがありました。
- no-unexpected-multiline
これを設定すると、例えばセミコロンなしで設定しても以下のように警告してくれます
/* eslint semi: ["error", "never"] */ /* eslint no-unexpected-multiline: "error" */ const foo = {} // ここはセミコロン無しだと警告がでる (function() { return 1 // ここはセミコロン有りだと警告がでる })()
す、すごい…… 私はセミコロン有り派でしたが食わず嫌いをしていました。 これならセミコロン無しでもいいかな、という気になっています。
閾値が難しいもの
「コードの複雑さでエラーにする」という所で、
max-depth
や max-nested-callbacks
と似たような以下の設定があります。
これらはどこからエラーにするか判断が難しいので設定しないことにしました。
ルール | 内容 |
---|---|
complexity | 複雑度が設定を超えるとエラー |
max-len | 1行の長さが設定を超えるとエラー |
max-lines | 1ファイルのステップ数が設定を超えるとエラー |
max-params | 引数の数が設定を超えるとエラー |
max-statements | 変数の数が設定を超えるとエラー |
max-statements-per-line | 1行に存在する変数の数が設定を超えるとエラー |
迷ったもの
入れるか迷った場合は入れないようにしました。 ほとんどのルール設定で入れるか迷った部分が多かったんですが、 特に迷ったのがこちらです。
ルール | 内容 |
---|---|
valid-jsdoc | 有効なJSDocコメントかチェックする |
no-eq-null | == , != によるnull比較を禁止する |
no-magic-numbers | マジックナンバーを禁止する |
no-return-await | return文にawaitを使うことを禁止する |
no-throw-literal | 例外として投げられるものを制限する |
no-warning-comments | TODOやFIXEME等の警告コメントを禁止する |
prefer-promise-reject-errors | Promiseのrejectに渡せるものを制限する |
require-await | awaitを使っていないasync関数を禁止する |
yoda | yoda("red"===color のような左右を逆にすべき)条件を禁止する |
consistent-this | self = this のようにthisを代入する変数名を統一する |
require-jsdoc | JSDocコメントを必須にする |
unicode-bom | BOMを必須または禁止する |
no-duplicate-imports | 重複したモジュールのimportを禁止する |
no-var | varの使用を禁止する |
Node.js and CommonJS
ESLintにはNode.js用のルール設定があります。 今回はwebpackなどの設定にしかNode.jsのコードがないので入れませんでした。
Node.jsのコードを開発で使う場合は設定しておくと助けになると思います。
ESLintの全てルールを確認してみて
どうだったでしょうか。 意外と知らないことが結構あったのではないかと思います。 私としてはいくつか大きな収穫がありました
1. ESLintに怒られても動じない
ESLintに怒られてもすぐ意味がわかるようになったので、 怒られるストレスがほとんどなくなりました。
2. 厳しい設定から緩くするのもアリ
自分が把握していないルール設定は使いたくないという気持ちがあったんですが、 ESLintのルール設定は有用なものがほとんどだと分かったので、
- 厳しいルール設定(airbnbなど)を元に、設定を引いて緩くする。
この方法で設定するのもアリだと自信を持って言えるようになりました。
3. コード品質への貢献度が想像以上
コードのスタイルに関することがメインだと思っていましたが、 複雑度チェックやネスト数のチェック、無意味なelseのチェックなど、 コードの品質を直接あげる機能が思った以上に優秀でした。 経験の浅いメンバーにとって良いチェックツールになります。
4. 自動修正で時短コーディング
どこまで--fix
で自動修正できるか把握できるようになったので、
自動修正できるものは自動修正に任せるようになりました。
スペースやセミコロンを抜いて書けるので、コーディング時間の短縮になりました。
最後に
メリットばかりのESLint。 全部の設定を確認するのは大変ですが、 一度確認しておくことをオススメします。 マネーフォワードでは、様々な雇用形態でエンジニアを募集しています。 ご応募お待ちしています。
【採用サイト】 ■マネーフォワード採用サイト ■Wantedly | マネーフォワード
【プロダクト一覧】 自動家計簿・資産管理サービス『マネーフォワード』 ■Web ■iPhone,iPad ■Android
ビジネス向けクラウドサービス『MFクラウドシリーズ』 ■会計ソフト『MFクラウド会計』 ■確定申告ソフト『MFクラウド確定申告』 ■請求書管理ソフト『MFクラウド請求書』 ■給与計算ソフト『MFクラウド給与』 ■経費精算ソフト『MFクラウド経費』 ■入金消込ソフト『MFクラウド消込』 ■マイナンバー管理ソフト『MFクラウドマイナンバー』 ■資金調達サービス『MFクラウドファイナンス』
メディア ■くらしの経済メディア『MONEY PLUS』