webpack 5でCSSを別ファイルに書き出し&minifyをする方法

公開日:

目次

webpack 5でCSSを別ファイルに書き出し&minifyをする方法

今回はwebpack 5でCSSを別ファイルに書き出し&minifyをする方法を紹介します。通常、webpackでcssをバンドルするときは style-loader を使用してJavaScriptからDOMにCSSを挿入することが多いかと思います。しかし、最近では、JSファイルにバンドルせず、CSSファイルとして別ファイルに書き出す運用をしたいという場面がでてきました。僕も実際にそういった場面に出くわして、その実装にかなり時間がかかってしまったので、備忘録としてブログに残しておきたいと思います。

mini-css-extract-pluginでCSSを分割

まず、 style-loader を使用して JavaScript からCSSをDOMに挿入しているところをCSSを別ファイルとして書き出すようにしたいと思います。CSSを別ファイルとして書き出すようにするには mini-css-extract-plugin という webpack のプラグインを使用します。
以下のように npm からインストールします。

npm i -D mini-css-extract-plugin

webpack.config.jsには以下のように記述します。

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  plugins: [new MiniCssExtractPlugin()],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
    ],
  },
};

こうすることでJSファイル内で読み込まれていたCSSファイルがバンドルされたJSファイルとは別のCSSファイルとして書き出されます。
JSファイル内で読み込むだけでなく下記のように entry として指定しても大丈夫です。

entry: {
    'bundle': './src/index',
    'bundle': './src/style.css',
},

さらに、書き出しするファイル名も指定することができます。指定の仕方は [name].css とすることで entrykey として指定した文字列が [name] に入ってきます。上記の場合だと bundle.css として書き出されます。また、ファイル名を直接指定して書き出すこともできます。指定の仕方は以下になります。

new MiniCssExtractPlugin({
      filename: '[name].css', // 'hoge.css' のように直接指定することも可能です。
}),

CssMinimizerPlugin でCSSをminifyする。

MiniCssExtractPlugin でCSSを別ファイルとして書き出すことができるようになりました。しかしその書き出したCSSファイルはminifyされていません。次は CssMinimizerPlugin を使用してminifyしたCSSファイルを書き出せるようにしたいと思います。
まずは、プラグインをnpmからインストールします。

npm i -D css-minimizer-webpack-plugin

追加できたら、webpack.config.js を以下のように編集します。

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
  optimization: {
    minimizer: [
      // For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
      // `...`,  ここを追加することでjsのminifyの設定を維持しつつcssをminifyできる(スプレッド演算子のイメージ)。
      new CssMinimizerPlugin(),
    ],
  },
};

補足ですが、 optimize-css-assets-webpack-plugin はwebpack5から非推奨になり、CssMinimizerPlugin が推奨されています。(最初、 optimize-css-assets-webpack-pluginを使用したのですが、jsのminifyができませんでした。)

webpack-remove-empty-scripts で不要なJSファイルを削除する

JSとCSSを別ファイルとして書き出し、CSSをminifyすることはこれまででできるようになりました。
しかしまだ懸念点があります。それは、mini-css-extract-plugin でCSSを別ファイルとして書き出した場合、不要なJSファイルが webpack での output先のディレクトリに生成されてしまうことです。
なにか問題があるわけではないのですが、少し気持ち悪いです。
この問題を解決するために広く使用されているライブラリが webpack-fix-style-only-entries です。しかし、webpack-fix-style-only-entries のリポジトリを見ると、

The current package version is not compatible with webpack 5.

と表記されています。実際にwebpack5 で webpack-fix-style-only-entries を npmインストールして使用してみると、ビルド時にエラーが発生してしまいました。
結論としてこの解決策は webpack-remove-empty-scripts を使用することです。webpack-fix-style-only-entries の README にも webpack5の場合は webpack-fix-style-only-entries を推奨するような書き方がされています。
使い方は以下のとおりです。 まず、npm or yarn でインストールします。

npm i -D webpack-remove-empty-scripts

そして、webpack.config.js の pluginに設定を追加します。

// webpack.config.js

plugins: [
        new RemoveEmptyScriptsPlugin(),
   // other plugins...
    ],

簡単なことにこれで設定は完了です。これでビルドすると先程は生成されていた 不要な JSファイルが生成されなくなりました。

まとめ

今回はwebpackでcssを別ファイルとして出力したいときの方法について説明しました。cssを別ファイルとして出力すると rel="preload"を使用してCSSを非同期で読み込ませることでパフォーマンス改善なんてこともできるようになります。