webpackのローダの設定を混ぜるな
概要
小ネタです。webpackには、動作を拡張できる「ローダ」という仕組みがあるのですが、その動作を設定ファイル(webpack.config.js
)で変更することができます。今回はここの書き方でハマったという話です。
対応バージョン
$ webpack --version 4.8.1
ローダでのオプション設定、2つの方法
css-loader
というローダがあります。これを使うと、複数のCSSファイルをまとめたり、JavaScriptの中でCSSのStyleを適用できたりします(CSS modules)。今回、このCSS modulesを利用している中でCSSのクラス名の命名について、kebab-caseからcamelCaseに変更したいと思った時にハマりました。
css-loader
をwebpackに組み込む最もシンプルなコードは以下です。
module.exports = { module: { rules: [ { test: /\.css$/, use: ['css-loader'], }, ], }, };
これで、.css
で終わるファイルに関して、css-loader
が動作するようになります。これらの動作を変更するためのオプションが用意されているのだが、その書き方には大きく2種類あって、1つ目は以下のように、ローダ名文字列をoption
属性を持つオブジェクトに置き換える方法です。
module.exports = { module: { rules: [ { test: /\.css$/, use: [ { loader: 'css-loader', options: { modules: true } } ] } ] } };
そしてもう一つ、「インライン」方式があって、URLのクエリパラメータと同様の形式の文字列を与えることができます。上記と同様の内容をインライン形式で記述すると、以下のようになります。
module.exports = { module: { rules: [ { test: /\.css$/, use: ['css-loader?modules=true'], }, ], }, };
2つの指定方法を混ぜてはいけない
本題に入ります。css-loader
にはlocalsConvention
というオプションがあります。
少し説明します。(少なくとも個人的には)CSSファイルに記述するクラス名は通常kebab-caseで、JavaScriptでの属性名はcamelCaseで記述するのですが、css-loader
のデフォルトではCSSクラス名からJS属性名へ何の変換も行いません。したがって、どちらかのケースに統一する必要があります。でもCSSにcamelCaseが書いてあるのも、JSにkebab-caseが堂々と出てくるのもあまり好きではないので、名称の変換をしたいわけです。
今回、希望の動作を叶えるためには、localsConvention
にdashes
を指定します。
module.exports = { module: { rules: [ { test: /\.css$/, use: [ { loader: 'css-loader?modules', options: { localsConvention: 'dashes' } } ] } ] } };
しかしながら、実は上記の設定は正しく動作しません。実際には、該当するCSSクラスが全て効かなくなってしまいました。2つの方式を混ぜて書いてしまっているからです。しかもタチの悪いことに、ビルド時エラーにもなりません。
正しい指定方法
2つの方式は共存できないので、以下のどちらかで統一しましょう。
ちなみにインライン方式ではmodule=true
ではなく、module
になっています。オプション名だけだと=true
を付けたのと同じことになるみたいですね。初歩的な内容かもしれません。あんまり詳しくなくてごめんなさい。
オブジェクトでの指定
module.exports = { module: { rules: [ { test: /\.css$/, use: [ { loader: 'css-loader', options: { modules: true localsConvention: 'dashes' } } ] } ] } };
インライン方式での指定
module.exports = { module: { rules: [ { test: /\.css$/, use: ['css-loader?modules&localsConvention=dashes'], }, ], }, };