こんにちは、ForSchool事業部の石上です。
あるSPAを作る際、CSSを書きやすくするためにいくつかWebpackの設定を書きました。 今回は、これらの設定がなぜ今こうなっているのかを社内のメンバーに説明するつもりで、どれが何のために必要な設定なのかを書いてみます。
背景
ウェブフロントエンド全般に言えることですが、CSS周りにもツールや設定方法はたくさんあります。一から用意する際は、毎回何を選んでどうすればいいのか悩んでしまいます。そこで今回のプロジェクトに使う設定をやりたいことベースで整理したところ、以下のような要件となりました。
- 配信するときは1ファイルで、なるべくサイズを小さくしたい
- コンポーネントごとにスタイルを閉じたいけど、BEMは面倒
- デザイナーさんに用意してもらった変数を一箇所で管理したい
- ベンダープレフィックスを自動でつけてほしい
設定
MiniCssExtractPlugin
その前段階で何をするにしろ、最終的にはサイズを小さくした1つのCSSファイルに出力したいです。これにはMiniCssExtractPluginを使います。
CSS Modules
BEMという設計方法があります。Block, Element, Modifierに分ける命名規則です。
class名をblock__element--modifier
の形にすることで、コンポーネント間の名前の衝突を避けることができます。
しかし、グローバルで一意な名前を付けるためにクラス名は長くなり、命名も面倒になってくるという問題があります。
そこで、CSS Modulesという仕様があります。
今回のプロジェクトでは、モジュールバンドラーにWebpackを利用しているので、Webpackのloaderを利用します。
CSS Modules形式で書いたCSSをcss-loader
というloaderに通し、これを実現しました。
typed-css-modules
CSS Modulesを使って、CSSをJavaScript側からモジュールのように参照できます。
TypeScriptで書いている場合は、これに型を付けたくなります。
import * as styles from './styles.scss'
こういうものに対して、
<p className={styles.hoge}> </p>
こう書いて参照しようとすると、エラーになります。stylesの型が決まっておらず、styles.hoge
の存在を認識できないからです。
そこで、以下のようなファイルをstyles.d.tsとして用意してhogeを定義しておくと、このエラーはなくなります。
export const hoge: string;
これを自動でやってくれるのが、typed-css-modulesです。
作者のQuramyさん的にはバンドルの前にd.tsを生成しておくべきという意向のようで、loaderが提供されていません。ただこれが必要だと思う方もいて、loaderを書いた方がいました。CSSを変えるたびにコマンドを打ったりしないといけないのは面倒なので、そちらを使っています。
ここまでの流れはこうなりました。
Sass
今回のプロジェクトでは、デザイナーさんがInVisionのDSMというツールで、色の変数などを管理しています。Sketchから上げられたこのデータを、DSM上でSassの変数として出力することができます。 これをそのまま使うべく、Sassも利用することにしました。
Webpackでの設定にはsass-loaderというものがあり、これを使いました。
先程のCSS Modulesの設定に加えると、流れは以下のようになります。
PostCSS
ベンダープレフィックスを一つずつ手で書きたくなかったため、自動でベンダープレフィックスを付けてくれるautoprefixerの設定も必要でした。
以上までで、バンドリングの流れはこうなりました。
まとめ
ここまでで紹介したものは、最先端のイケてる設定というよりは、必要なものをなるべく単純に実現するための設定だと認識しています。
実際これを書きながら、
「DSMの変数をそのまま利用するためにSassを入れたが、これはCSS Modulesのcomposesで表現するべきでは?」
とか、
「最近はstyled-componentsがイケているというのをよく聞くし、CSS Modulesだと何か困ることがあるのか…?」
みたいな迷いも出てきました。最適化できる部分はまだありそうです。
今後も粛々と、ビルド設定を保守・改善していこうと思っております。