Sansan Builders Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

SCSS-Lint から stylelint に移行した話

こんにちは。Eight でフロントエンドエンジニアをしている鳥山(@pvcresin)です。
ついこの間新卒で入ったと思ったら、もう 2 年目に突入していました。時が経つのは早いものです。
今回は Eight の Web フロントエンドで使っているスタイルのリンター(コードの静的解析ツール)を SCSS-Lint から stylelint に移行した話をしたいと思います。

SCSS-Lint

Eight のフロントエンドではスタイリングに Sass(SCSS 記法)を使用しています。 そして、そのリンターとして SCSS-Lint を採用していました。 それをコードレビュー自動化ツールの Sider(旧 SideCI)と組み合わることで、PR(プルリクエスト)上で SCSS ファイルをチェックするように設定していました。 これによりスタイル定義の品質を担保していました。

SCSS-Lint が非推奨に

しかし、大きく風向きが変わる出来事が起こります。
元々 Ruby で実装されていた Sass ですが、2016 年 10 月に Sass のコアチームが実装を Dart に乗り換えると発表したのです。 Ruby Sass は以前から動作が遅いことが問題視されており、動作速度と開発のしやすさのバランスを考えた結果生まれたのが Dart Sass でした。1 今後 Ruby Sass では最新の機能が実装される保証がなくなるため、それに依存していた SCSS-Lint も最新の記法に対応できない可能性が出てきました。 その影響により、Sider での SCSS-Lint の利用が非推奨となってしまったため、Eight では 2020 年 3 月に Sider を使った PR チェックを停止しました。
このままにしておくとスタイルの定義が大変なことになるのは目に見えていたので、一念発起して SCSS-Lint から別のリンターに移行することを決めました。

stylelint

そこで白羽の矢が立ったのが stylelint でした。 stylelint は多数のルールが用意されており、プラグインによる柔軟なカスタマイズが可能なリンターです。 CSS の最新の構文に対応しており、HTML や Markdown などに埋め込まれたスタイル定義にも対応することができます。 プラグインを使えば SCSS の構文にも対応でき、SCSS-Lint でも移行先の候補として紹介されています。
加えて、コード整形ツールの Prettier とも連携できるため、stylelint に移行することを決めました。

移行手順

ここからは実際の作業について説明します。
前提として、既存のスタイル定義には手を加えず、Lint エラーは積極的に disable コメントなどで潰していきました。

1. 対応するルールの洗い出し

SCSS-Lint と stylelint は全くの別物なので、今まで SCSS-Lint で使っていたルールに対応するものを stylelint とプラグインで実現できるか調べるところからはじめました。 今回、SCSS-Lint のルールを再現するのには、以下の3つのプラグインを利用しました。

対応するルールの例は以下のようになります。

SCSS-Lint stylelint
!important を禁止 ImportantRule declaration-no-important
id の使用を禁止 IdSelector selector-max-id
空のセレクタを禁止 EmptyRule block-no-empty
変数の命名規則を強制 NameFormat scss/dollar-variable-pattern

ほとんどのルールは対応するものが見つかりましたが、一部は stylelint で実現することが難しかったので諦めました。

2. Prettier との連携

先ほど述べたように、stylelint と Prettier は連携させることができます。 連携の方法はいくつかあるのですが、今回は Prettier の整形ルールを stylelint の1ルールとして扱う方法をとりました。 連携には以下の 2 つを利用しました。

stylelint にはコードのチェックと同時に簡単なルール違反であれば自動でコードを修正する機能(stylelint --fix)があります。 stylelint-prettier を使うことで、自動修正時に内部で Prettier の自動整形を走らせることができます。
また、Prettier のルールとぶつかる stylelint のルールの定義は不要なので、stylelint-config-prettier が持つstylelint-config-prettier-checkコマンドを使ってルールを洗い出して削除しました。
これで準備は整いました。ここからは実際の SCSS ファイルを書き換えていきます。
作業の進め方としては、以前 JavaScript のファイルに Prettier を適用した時と同様です。

Eight フロントエンド、Prettier 入りました - Sansan Builders Blog

3. 既存のコードのチェック + 整形

まず、あらかじめコードをチェック + 整形する範囲を決めました。
その一定の範囲内のファイルで、SCSS-Lint の disable コメントを消し、必要なところに stylelint の disable コメントを追加していきました。 stylelint を効かせたくないファイルについては .stylelintignoreファイルを活用しました。
諸々の修正を行った後、stylelint --fixコマンドを実行して自動修正(整形)を行い、エラーが残っていないことを確認しました。

4. 新規のコードのチェック + 整形

Git のフックを利用し、一定の範囲内のファイルのコミット時にチェック + 自動修正(整形)をかけるようにしました。 これには Huskylint-staged を使いました。

5. CI の整備

一定の範囲内のファイルがちゃんと stylelint のルールに準拠しているかをチェックするように、CI の設定を追加しました。 Eight フロントエンドではメインの CI として CircleCI を使っているので、job に stylelint コマンドを実行する step を追加しました。 当初はこれまで通り Sider を使おうと考えていたのですが、稀に stylelint でのエラーを見逃してしまうケースがあり、 CircleCI でチェックすることとしました。
これにより新しいコードはほぼ確実に stylelint のルールに準拠した状態でマージされることになります。

6. 「一定の範囲」を広げる

手順の 3~5 で、一定の範囲内では既存のコードも新規のコードも stylelint のルールに準拠していることが保証されるので、あとは範囲を広げていくのみです。
少しずつ範囲を広げながら PR を出していきました。

作業を終えて

個人のサイドタスクとして進めていたのですが、フロントエンドのコード全体に stylelint を広げるのは、2 週間ほどで終わりました。 元々 SCSS-Lint でチェックされていたルールを移植したので、大きな差分もありませんでした。 画面崩れもなく無事に終えることができてよかったです。

まとめ

今回は、Eight の Web フロントエンドで使っているスタイルのリンターを SCSS-Lint から stylelint に移行した話について書きました。
stylelint は非常に柔軟にカスタマイズでき、様々なニーズに対応できるツールだなと感じました。 また、Prettier と連携させることでコードの整形も同時に導入でき、PR も見やすくなったと感じます。
最近、後輩エンジニアが入ってくる中で、何を伝えられるのか、何を伝えるべきなのかを考えるようになってきました。 少なくとも Lint エラーの指摘は私が伝えるべきことではないので、少しは伝えるべきことに注力できるようになったかなと思います 😄


  1. Ruby Sass は開発はしやすいが動作が遅く、C/C++で実装されている LibSass は動作は速いが開発がしづらいという評価を受けていました。そこで第3の選択肢として現れたのが Dart Sass でした。

© Sansan, Inc.