概要
- Vue(前バージョン共通)でwebpackビルドしている
- Vueファイル内のstyleタグではCSSmoduleを使いたい
- node_modulesに入っているCSSは純粋なCSSとしてグローバル反映させたい
- よくあるgetting started章のドキュメントの通りにコピペするとCSSmoduleにならないか、直接クラス指定したいスタイルが反映されなくなってしまう
上記の状況の際に、雑にCSSmoduleを有効化するとnode_modulesのCSSまでクラス名がハッシュ化されてしまい、不便が発生する場合の対処法。
もしかしたらReactでもelement-plusのような設計のライブラリがあれば起こるかもしれない
自分の場合だと elementUI にて発生したので綴る。
環境
- Vue 3.0.7
- Webpack 5.26.2
- css-loader 5.1.3
- element-plus 1.0.2-beta.35
対策
node_modules内のCSSはnot CSSmoduleとして読み込む
※以下例ではsass-loaderも使っていますが、sassを使用しない場合は無視してください
{
/* 〜〜〜〜略〜〜〜〜 */
module: {
rules: [
/* 〜〜〜〜略〜〜〜〜 */
{
test: /\.(sa|sc|c)ss$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
modules: true
}
},
'sass-loader',
]
}
/* 〜〜〜〜略〜〜〜〜 */
]
}
/* 〜〜〜〜略〜〜〜〜 */
}
こんな風にwebpack.config.jsが書かれていると思うが(vue-loaderのオプションに書いている人はvue-loaderの loader.options.loaders.[任意の拡張子]
等を参照)、このままwebpackを通すと、node_modules内のCSSもCSSmoduleと解釈されるため、CSSライブラリを使うなどしてどうしてもVueテンプレート内に生のクラスで書きたい場合や、 element-plus
あるいは element-ui
のようにVueファイル内で別途CSSを外部から当てないとimportしたコンポーネントにスタイルが当たらない 使いづらい 仕様のライブラリでは外部CSSまでCSSmoduleとしてクラス名がハッシュ化されてしまうとコンポーネントライブラリのデザインが適用されなくなってしまう。
ここでの問題は、 node_modules
の中にあるCSSまでCSSmoduleになることが問題なので、ならばnode_modules
内はCSSmoduleでは無いものとしてwebpackに食わせれば良い。すなわちこうなる
{
/* 〜〜〜〜略〜〜〜〜 */
module: {
rules: [
/* 〜〜〜〜略〜〜〜〜 */
{
test: /\.(sa|sc|c)ss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader',
],
include: /node_modules/,
},
{
test: /\.(sa|sc|c)ss$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
modules: true
}
},
'sass-loader',
],
exclude: /node_modules/,
},
/* 〜〜〜〜略〜〜〜〜 */
]
}
/* 〜〜〜〜略〜〜〜〜 */
}
webpackは配列のconfigでは末尾から処理されていくので、末尾側に options.modules: true
にしたcss-loaderをセットして、 exclude: /node_modules/
する。
次に、先頭側に options.modules: false
にした include: /node_modules/
する。
webpack5のドキュメントによれば
Exclude all modules matching any of these conditions. If you supply a Rule.exclude option, you cannot also supply a Rule.resource.
マッチした全てのモジュールを除外する
Include all modules matching any of these conditions. If you supply a Rule.include option, you cannot also supply a Rule.resource.
マッチした全てのモジュールを含める
つまり、これを組み合わせたルールを2重に定義することで、特定ディレクトリは純粋なCSSファイルとして、特定ディレクトリはCSSmoduleとしてwebpackに食わせることができる。
ちなみに、先頭側のcss-loaderルールから include: /node_modules/
を外してしまうと、既にwebpackを通しているcssが再度読み込み直されてしまうので注意。
所感
(カスタム性上げたい気持ちはわかるが)令和の時代にESmodule importで完結しない上にbabelを通さないとCSSをグローバル反映させる必要があるようなコンポーネントライブラリを作るな・・・