フロントエンドにESLint、Prettier、stylelintを導入して快適な開発環境を整えました
こんにちは、Webチームの柴山(@shikeapp0909)です。
私たちのプロダクト「ままのて」のフロントエンドはReact + SCSSで開発しています。コード規約は存在するもののインデントやセミコロンのつけ忘れなどをいちいちコーディングの際に気をつけながら開発するのも、コードレビューでチェックして防ぐのも余計な労力で効率が悪いため、リントとコードフォーマッターを入れることにしました。
今回はその導入内容を手順と共にご紹介します。
JSのリントとフォーマッター
JSの方はESLintとPrettierでリントとフォーマットを行うようにしました。
JavaScript Standard Style
基本的なJSのコード規約はJavaScript Standard Styleに準拠することとしました。
公式から簡単にルールを抜粋すると、以下のようになっています。
- インデントは2スペース
- 文字列はシングルクオート
- 未使用変数は禁止
- 文末セミコロンは禁止
- キーワードの後にスペースを入れる
- 関数名の後にはスペースを入れる
- 値の比較には
==
ではなく===
を使う
こちらの記事が詳しく解説してくださっていますので、読んでみてください。
JavaScript Standard Styleのススメ - Qiita
これをESLintのルールとして適用するようにしています。そのためのプラグインが用意されているので、ESLint本体とそれらをインストールします。
$ yarn add -D eslint eslint-config-standard eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node
※yarnは適宜npmと読み替えてください。
そしたらpackage.json
と同じディレクトリに.eslintrc.yml
ファイルを作成し、以下のように記述します。
extends: - standard
これだけでESLintにJavaScript Standard Styleの設定は完了です。
React用のESLint
次にReact用の設定です。こちらもESLint用のプラグインが用意されているので、それをインストールします。
$ yarn add -D eslint-plugin-react eslint-plugin-jsx-a11y
そしたら先ほどの.eslintrc.yml
に追記します。
extends: - standard # ↓追加 - plugin:react/recommended plugins: - react settings: react: version: 16.6 # お使いのReactのバージョン # ↑追加
これで、Reactのバージョンに応じてDeprecatedになったAPIをしようしていないかなどをチェックしてくれます。
このルールではPropTypes
の定義が必須なのですが、既存のコードではPropTypes
をまったく記述していなかったので、今回はこのルールをいったん除外することにしました。そのためには.eslintrc.yml
のrules
に追加します。
extends: - standard - plugin:react/recommended plugins: - react # ↓追加 rules: react/prop-types: - 0 # ↑追加 settings: react: version: 16.6 # お使いのReactのバージョン
これでPropTypes
を定義していなくても怒られなくなりました。
Prettier
最後にPrettier
の設定です。Prettier
はJSだけでなくCSSなどさまざまなファイルをフォーマットしてくれる便利なプラグインです。設定できるルールについては、公式ドキュメントで確認してください。
Prettierのデフォルトのルールは先ほどのJavaScript Standard Styleと重複していて相反するものがいくつかあるので、カスタマイズして使用するため、.prettierrc.yml
ファイルを.eslintrc.yml
ファイルと同じディレクトリに作成し、以下のように記述します。
printWidth: 120 semi: false singleQuote: true trailingComma: es5
デフォルトだと80文字を越えると改行されますが、それだと少し短いと感じたので、とりあえず120文字と設定し、配列とobjectには最後のプロパティの後ろにカンマを入れるように設定しました。
これでPrettier
の設定はできましたが、こちらに記載されているように、Prettierの設定をESLintに取り込んで、ESLintのルールとして実行することが可能です。そのためのプラグインをインストールします。
$ yarn add -D eslint-plugin-prettier eslint-config-prettier
そしたら.eslintrc.yml
ファイルに以下を追加します。
extends: - standard - plugin:react/recommended - prettier # ←追加 plugins: - react - prettier # ←追加 rules: react/prop-types: - 0 # ↓追加 prettier/prettier: - error # ↑追加 settings: react: version: 16.6 # お使いのReactのバージョン
eslint-plugin-prettier
の方はESLintのルールとしてPrettierのルールを読み込んで処理するプラグインで、eslint-config-prettier
はESLintで設定されているルールとPrettierのルールが重複しないようにするためのプラグインです。
これでESLintとPrettierの設定の統合までできました。
グローバル変数などの対応
このままだと、window
やjQueryの$
などのグローバル変数などが未定義の変数として怒られてしまうので、それらを除外するための設定を.eslintrc.yml
に追加します。
extends: - standard - plugin:react/recommended - prettier plugins: - react - prettier # ↓追加 env: browser: true jquery: true globals: googletag: true ga: true # ↑追加 rules: react/prop-types: - 0 prettier/prettier: - error settings: react: version: 16.6
env
のbrowser: true
でwindow
などが、jquery: true
でjQueryの$
が怒られなくなります。
globals
にはその他に除外したいグローバル変数を追加すると怒られなくなります。今回はGoogle AnalyticsやGoogle Adsenseなどのグローバル変数が定義されているので、それらを除外しました。
これでESLintはすべての設定が終わりました。
npm scriptを設定する
後はnpm scriptでリントを実行できるようにします。
package.json
のscripts
に以下のように記述します。
"scripts": { "eslint": "eslint -c .eslintrc.yml --color './src/**/*.{js,jsx}'", "eslint:fix": "eslint -c .eslintrc.yml --color './src/**/*.{js,jsx}' --fix" }
これでyarn eslint
でESLint実行、yarn eslint:fix
でESLint実行と自動フォーマットができるようになりました。
webpackビルド時にESLintを実行するようにする
webpackを使っている場合は、ビルド時にESLintを実行させることも可能です。そのためにはeslint-loader
をインストールします。
$ yarn add -D eslint-loader
そしたらwebpackの設定ファイルに追加します。
module.export = { ... module: { rules: [ { enforce: 'pre', test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'eslint-loader', options: { fix: true, configFile: '.eslintrc.yml', }, }, ... }
上記のように、loader
の設定を追加するだけで、ビルド時にESLintを実行してくれます。enforce: 'pre'
を指定することで、webpackビルド前に実行してくれるようになります。options
にfix: true
を指定して、自動フォーマットまでするようにしたかったのですが、うまく機能してくれてません。。。公式を見る限りではこれだけでやってくれそうな感じなのですが。。。原因がわかる方いらっしゃったら教えていただきたいです。
エディターの設定
後はお使いのエディターのプラグインに、ESLint用のものがおそらくあるかと思いますので、それをインストールすれば、自動で設定ファイルを読み込んでコーディング時にリアルタイムでリントしてくれるようになると思います。ファイル保存時にフォーマットを実行するオプションを使えば、さらに快適にコーディングできると思います。ちなみに私はVS Codeを使用しています。
SCSSのリント
SCSSのリントには、stylelintを選びました。FacebookやGitHub、WordPressでも使用されており、豊富なルールが用意されていて、導入事例も増えているように思います。何よりもESLint同様自動フォーマットオプションがついているのが大変ありがたいです。
導入
stylelint本体と、公式でも取り上げられているプリセットルール、そしてSCSS用のプラグインを入れます。
$ yarn add -D stylelint stylelint-config-standard stylelint-scss
stylelint-config-standard
の他にstylelint-config-recommended
もありますが、すごくざっくり言うと後者は最小限のルールのみで、前者がstylelint-config-recommended
を拡張したもので、よりかっちりしたルールといった感じでしょうか。今回は詳細なルールを決めてより統一感のあるコードにしたかったので、stylelint-config-standard
を選択しました。
インストールしたら、ESLint同様、.stylelintrc.yml
ファイルを作成し、以下のように記述します。
plugins: - stylelint-scss extends: - stylelint-config-standard syntax: - scss rules: at-rule-no-unknown: null scss/at-rule-no-unknown: true
SCSSの@extend
などの機能を使う場合、at-rule-no-unknown
は対応しておらず怒られてしまうため無効にしないといけません。代わりにscss/at-rule-no-unkwon
を有効にすることで対応できます。
次に、プロパティのソート順をリントしてくれるプラグインを入れます。今回はstylelint-config-recess-order
を入れました。これはstylelint-order
をベースに、機能単位でのソート順が定義されています。
$ yarn add -D stylelint-config-recess-order
インストールしたら、.stylelintrc.yml
に追加します。
plugins: - stylelint-scss extends: - stylelint-config-standard - stylelint-config-recess-order # ←追加 syntax: - scss rules: at-rule-no-unknown: null scss/at-rule-no-unknown: true
また、ままのてでは上記の他にもまだ定義できるルールがいくつかあるので、そちらも定義しています。
plugins: - stylelint-scss extends: - stylelint-config-standard - stylelint-config-recess-order syntax: - scss rules: at-rule-no-unknown: null scss/at-rule-no-unknown: true at-rule-no-vendor-prefix: true # @ルールのベンタープリフィックス禁止 font-family-name-quotes: always-where-recommended # 'font-family'はスペースで区切られたフォント名の場合クオートで囲む font-weight-notation: named-where-possible # 'font-weight'はnormalなどのキーワードが使える場合はそちらを使う(400はNG) function-url-quotes: always # 'url()'の引数はクオートで囲む media-feature-name-no-vendor-prefix: true # '@media'内のベンダープリフィックス禁止 no-descending-specificity: null # 詳細度の高いセレクタより後に詳細度の低いセレクタを定義するのを許容 property-no-vendor-prefix: true # プロパティのベンダープリフィックス禁止 selector-attribute-quotes: never # '[type=text]'などのセレクタの属性はクオートで囲まない selector-no-vendor-prefix: true # セレクタのベンダープリフィックス禁止 string-quotes: single # 文字列はシングルクオートで囲む value-no-vendor-prefix: true # 値のベンダープリフィックス禁止
no-descending-specificity
については、オンにしている場合にSCSSで開発していると、たとえば以下のような場合このルールに引っかかります。
textarea { width: 100%; &:focus { outline: none; } }
どうやらこれはtextarea:focus
の方が先に評価されるらしく、このルールに引っかかるようです。そのため、このルールはオフにしています。
ベンダープリフィックス系はautoprefixer
を使っているのですべて禁止するようにしています。
ここまでできたら、npm scriptでリント実行できるようにします。package.json
に以下のように記述します。
"scripts": { "stylelint": "stylelint --config .stylelintrc.yml './src/**/*.scss'", "stylelint:fix": "stylelint --config .stylelintrc.yml './src/**/*.scss' --fix" }
これでyarn stylelint
でリント実行、yarn stylelint:fix
でリント実行と自動フォーマットができるようになります。
webpackビルド時にstylelintを実行するようにする
ESLint同様、stylelintもwebpackビルド時に実行するためのプラグインがあるので、そちらをインストールします。
$ yarn add -D stylelint-webpack-plugin
インストールしたら、webpackの設定ファイルのplugins
に以下のように追加します。
const StyleLintPlugin = require('stylelint-webpack-plugin') module.export = { ... plugins: [ ... new StyleLintPlugin({ configFile: '.stylelintrc.yml', }), ], ... }
これでwebpackビルド時にstylelintも実行されるようになりました。
エディターの設定
こちらもESLint同様、エディター用のプラグインが用意されているかと思いますので、そちらをインストールすればコーディング時にリアルタイムでリントしてくれるようになります。
まとめ
ESLintとstylelintをまた導入したばかりですが、確実に快適に開発できるようになって、生産性も上がっていると思います。万が一リントのエラーを見逃してコミットしても、ままのてではCIでリントを実行するように設定してあるので、そちらで拾ってくれるようになっています。実装者の負担も減るし、誰が書いてもスタイルの差が生じにくくなったと思います。
やはり快適に気持ちよく開発できる環境は大事だと改めて実感しました!
We're hiring!!
弊社ではWeb / ネイティブアプリエンジニアを募集しております。 ご興味がありましたらお気軽にご連絡下さいませ! エンジニアの方、ぜひ情報交換しましょう!
サーバーサイド
ネイティブアプリ