使われていないCSSルールを検出する stylelint-no-unused-selectors を作った
背景
発端はあるツイートより.
真面目な話、命名規則でCSSを管理する場合のdead code eliminationどうしてるのか知見ほしいマンです
— terrierscript (@terrierscript) March 1, 2019
たしかに CSS Modules は webpack の恩恵により,styled-components や emotion の場合にはその仕組みゆえに,どれも CSS の dead code elimination (使われていない CSS ルールが最終的な CSS ファイルに入らないようにすること) は自然と行われます.
一方で, CSS in JS なアプローチを取らない場合には往々にして challenging なものとなります.既存のツールとしては UnCSS, DropCSS, PurifyCSS, PurgeCSS などがあるものの,以下のような理由から自作することにしました.
- コンポーネントごとに CSS ファイルを分けて書いている場合 に使いづらいものが多かった
- jsx, tsx, CSS Modules, classnames にも対応したい
- コードを書いているときにリアルタイムで警告されてほしい
- stylelint の仕組みに乗っかるのが簡単そう
というわけで,以下のようなコンポーネントがある場合に,FooComponent.css と FooComponent.jsx のクラスを比較して, jsx 側で使われていないクラスがあったときに警告を出す stylelint プラグインである stylelint-no-unused-selectors が完成しました.
FooComponent ├── index.js ├── FooComponent.jsx └── FooComponent.css
使い方
stylelint と stylelint-no-unused-selectors をインストール.
yarn add -D stylelint stylelint-no-unused-selectors
その後 .stylelintrc に設定を追加すれば動くようになります.詳しくは README を参照してください.
{ "rules": { "plugin/no-unused-selectors": true } }
stylelint のプラグインがエディタで有効になっていれば,未使用の CSS を発見した場合に以下のようなエラーが出るはずです.
ターミナルで実行するとこんな感じ.
コード解析には @babel/parser と typescript を使っているので,TC 39 stage 4 未満の機能を使っている場合や,TypeScript で書かれている場合もサポートしています.
ちなみに600近くのコンポーネントがある某プロダクトでも試してみましたが,問題なく動作しました.
技術的な話
AST を本格的に扱うのは初めてだったので,どれから始めていいのかわからず途中まで acorn で作ってから後で @babel/parser (babylon) に移行するなど迷走してました. この界隈は玄人向けなのかあまりドキュメントがなく,かといって AST の仕様書やコードを直接読むのはかなりしんどいので,AST Explorer でいろいろいじくりまわして雰囲気で進めるのがよさそう.
JS/TS と比べると PostCSS 界隈はさらに情報が少なく,既存のプラグインのコードから挙動を推測する感じだったのが辛かったです...
おわりに
publish してから時間がなかなか取れずに記事を書けないでいたところ,なんと PostCSS の公式 Twitter が紹介してくれたのにはとても驚きました.
Stylelint plugin to find unused CSS selectors by @nodaguti.
— PostCSS (@PostCSS) May 22, 2019
Like uncss but in Stylelint with flexible options, CSS Modules and React support.https://t.co/2WdDyx7C3T pic.twitter.com/lH65p9OXgF
stylelint で使用されていないセレクターを警告するルールを作って、解説記事書こうと思っていたら公式 twitter で紹介された! 🎉 https://t.co/zOdSb4QTyC
— nodaguti (@nodaguti) May 22, 2019
しっかりしたドキュメントを書くことの重要性を改めて感じました(なかなか面倒臭がってしまいますが...).記事も英語版をどこかに投稿しないと,と思っています.
主に自分たちの課題を解決するために作り始めたプラグインですが,もし便利に思っていただける方がいましたらとても嬉しく思います!