この記事を読んでいて知ったのだが、CSSを抽出する目的でextract-text-webpack-pluginを使うのは非推奨になったらしい。
qiita.com
webpack@4では mini-css-extract-plugin というプラグインを使うことが推奨されている。
というわけで、その使い方を書いていく。
webpack でのCSSの扱いの基礎については、以前書いたこの記事を参照。
numb86-tech.hatenablog.com
本記事は以下のバージョンで動作確認している。
- webpack@4.20.2
- webpack-cli@3.1.2
- css-loader@1.0.0
- mini-css-extract-plugin@0.4.4
- optimize-css-assets-webpack-plugin@5.0.1
- terser-webpack-plugin@1.1.0
まずはCSSを webpack の対象にする
復習を兼ねて、動作確認用の環境を一から作っていく。
まずはwebpackとwebpack-cliをインストールする。
$ npm i -D webpack webpack-cli
webpack でCSSを扱えるようにするためにcss-loaderもインストールする。
$ npm i -D css-loader
今回はsrc/index.jsというファイルでsrc/style.cssを読み込んで使う。
// src/index.js import './style.css'; const body = document.querySelector('body'); body.innerHTML += 'Hello World!';
/* src/style.css */ body { color: red; }
最後にwebpack.config.jpを作成する。
// webpack.config.jp const path = require('path'); module.exports = { entry: { main: './src/index.js', }, output: { filename: '[name].js', path: path.resolve(__dirname, 'dest'), }, module: { rules: [ {test: /\.css$/, use: ['css-loader']} ], }, }
この状態で$ npx webpack --mode developmentを実行すると、dest/main.jsが生成される。
dest/main.jsには、src/index.jsとsrc/style.cssの内容が含まれている。
だがこのままでは、CSSの内容がアプリに反映されることはない。
CSSを実際に使えるようにするための方法の一つとして、extract-text-webpack-pluginがあった。
これは、webpack で出力した結果をテキストとしてファイルに抽出するプラグインで、これを使うことでCSSファイルを出力することが出来た。
webpack@4では、extract-text-webpack-pluginの代わりにmini-css-extract-pluginを使用する。
mini-css-extract-plugin の基本的な使い方
まずはインストールする。
$ npm i -D mini-css-extract-plugin
webpack.config.jpを以下のように書き換える。
// webpack.config.jp const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { entry: { main: './src/index.js', }, output: { filename: '[name].js', path: path.resolve(__dirname, 'dest'), }, module: { rules: [ { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', ], }, ], }, plugins: [ new MiniCssExtractPlugin({filename: 'style/[name].css'}), ], }
これで$ npx webpack --mode developmentすると、以下の内容のdest/style/main.cssが出力される。
body { color: red; }
また、dest/main.jsも更新され、src/style.cssの内容が省かれている。
あとはHTMLファイルでdest/main.jsとdest/style/main.cssを読み込めば正しく動作し、赤文字の「Hello World!」が表示される。
CSSファイルの圧縮
$ npx webpack --mode productionのようにprodcutionモードでビルドすると、JSファイルを圧縮してくれる。
先程の例だと、dest/main.jsがワンライナーに圧縮される。
だがdest/style/main.cssは何も変わらない。
mini-css-extract-pluginで抽出したCSSファイルを圧縮したい場合は、プラグインを使って明示的に設定する必要がある。
まずはプラグインをインストールする。
$ npm i -D optimize-css-assets-webpack-plugin
webpack.config.jsを以下の内容にする。OptimizeCSSAssetsPluginをrequireし、optimizationの記述を追加している。
const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); module.exports = { entry: { main: './src/index.js', }, output: { filename: '[name].js', path: path.resolve(__dirname, 'dest'), }, module: { rules: [ { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', ], }, ], }, plugins: [ new MiniCssExtractPlugin({filename: 'style/[name].css'}), ], optimization: { minimizer: [new OptimizeCSSAssetsPlugin({})], }, }
これで$ npx webpack --mode productionすると、dest/style/main.cssがワンライナーに圧縮される。
だが今度は、dest/main.jsが圧縮されていない。
実はoptimization.minimizerを記述すると圧縮の設定が上書きされてしまうので、JSについても明示的に設定しなければならない。
これまではJSの圧縮にはuglifyjs-webpack-pluginというプラグインを使っていたが、v2でES2015の対応が外れてしまった。今後ES2015+のコードを使う場合は、terser-webpack-pluginというプラグインを使う必要がある。
というわけで、terser-webpack-pluginをインストール。
$ npm i -D terser-webpack-plugin
そしてwebpack.config.jsを更新。
@@ -1,6 +1,7 @@ const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); +const TerserPlugin = require('terser-webpack-plugin'); module.exports = { entry: { @@ -25,6 +26,6 @@ module.exports = { new MiniCssExtractPlugin({filename: 'style/[name].css'}), ], optimization: { - minimizer: [new OptimizeCSSAssetsPlugin({})], + minimizer: [new TerserPlugin({}), new OptimizeCSSAssetsPlugin({})], }, }
これでビルドすると、dest/main.jsもdest/style/main.cssも圧縮される。