webpack 4とmini-css-extract-pluginを使ってCSSを別ファイルに書き出す方法
UI開発者 古川Vue.jsで単一ファイルコンポーネントを用いる際にCSSをひとつのファイルに書き出す方法は公式のドキュメントに掲載されています。しかしドキュメント内で紹介されているExtract Text Pluginの最新バージョン(v3.0.2)は2018年12月現在webpack 4に未対応なため、webpack 4の環境下で実際に導入するとエラーが出てしまいます。
そこで今回は、Extract Text Pluginで利用を推奨されているmini-css-extract-pluginを用いてVue.jsの単一ファイルコンポーネントに記述されているCSSを別のファイルに書き出す方法をご紹介します。
mini-css-extract-pluginの導入
webpack 4で単一コンポーネントを用いる準備が最小限整っている段階から始めます。
webpack.config.js
の設定は以下のコードです。
const VueLoaderPlugin = require('vue-loader/lib/plugin');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: `${__dirname}/dist`
},
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.(sc|c|sa)ss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader',
]
}]
},
plugins: [
new VueLoaderPlugin()
]
}
現段階で実行したファイルの状態が以下のキャプチャです。現段階でCSSは書き出されていません。
さっそく環境を整えていきましょう。まずmini-css-extract-pluginをダウンロードしたのち、webpack.config.js
を以下に変更します。
const VueLoaderPlugin = require('vue-loader/lib/plugin');
// mini-css-extract-pluginを読み込み
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: `${__dirname}/dist`
},
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.(sc|c|sa)ss$/,
use: [
// vue-style-loaderをMiniCssExtractPlugin.loaderに変更
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
]
}]
},
plugins: [
new VueLoaderPlugin(),
// MiniCssExtractPluginのインスタンスを追記
// ここで設定するfilenameは出力するファイル名
new MiniCssExtractPlugin({
filename: 'assets/css/app.css'
})
]
}
ローダーの設定順がポイントです。ローダーは記述順の後ろから前に実行されるため、
sass-loader
でSassをCSSにコンパイルcss-loader
でCSSの依存関係を解決mini-css-extract-plugin.loader
でCSSファイルの書き出し
という処理順を実行したい場合、上記のような記述となります。
この段階で実行した状態が以下のキャプチャです。CSSが書き出されています。
開発版とビルド版の出し分け
CSSファイルをひとつにまとめて出力する環境でwebpack-dev-serverを導入する場合は注意が必要です。
webpack-dev-serverはデフォルトではメモリ上のファイルを参照するのでバンドルしたファイルを出力しません。そのためwebpack-dev-serverを実行している状態でmini-css-extract-pluginを動作させても、ブラウザ上では出力された単一のCSSが読み込みされている状態が実現されますが実際にCSSファイルは出力されません。
上記の点を回避するために、Node.jsの環境変数を利用してdevelopment
モードの際はvue-style-loader
を用いてCSSをhead
内で読み込み、production
モードの際はmini-css-extract-pluginでCSSを出力するよう設定します。
今回は環境変数の利用においてプラットフォーム間の環境変数の記述の差分を吸収するcloss-envを導入します。closs-envをダウンロードしたあと、package.json
を以下のように記述します。
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server",
"build": "cross-env NODE_ENV=production webpack"
},
続いて環境変数に応じてwebpackのモードや読み込むローダーを切り替えるため、webpack.config.js
を以下のように設定します。
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 環境変数に応じて判定
const isDevelopment = process.env.NODE_ENV === 'development';
module.exports = {
// 判定に応じてモードを切り替え
mode: isDevelopment ? 'development': 'production',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: `${__dirname}/dist`
},
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.(sc|c|sa)ss$/,
use: [
// 判定に応じて実行するローダーを切り替え
isDevelopment ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
]
}]
},
// webpack-dev-serverの導入
devServer: {
contentBase: 'dist',
port: 3000
},
plugins: [
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: 'assets/css/app.css'
})
]
}
まとめ
extract-text-webpack-plugin v4.0.0 betaを使用すれば現状エラーが発生しませんが、次期バージョンの導入に不安を覚える方はmini-css-extract-pluginの導入を検討してみてはいかがでしょうか。