webpack 4ではPlugin(プラグイン)を使用しない場合、CSSの情報はwebpackの実行後に作成されるJavaScriptファイルに埋め込まれ、htmlファイルを閲覧する時にstyleタグにCSSの情報が埋め込まれます。しかし別ファイルのほうがいいという場合もあるため、webpackでは別ファイルにわけることができます。

別ファイルとして出力させるためにmini-css-extract-pluginを使用します。

webpack 3までは extract-text-webpack-pluginを使用してましたが、webpack4ではmini-css-extract-pluginを利用します。
fukidashi

環境の構築

mini-css-etract-pluginの動作確認を行うためにwebpackの環境を構築しておく必要があります。webpackはnpmを使ってインストールを行うのでnpmがわからない人は以下の記事を参考にしてください。

webpackのインストール

npmを使用してインストールを行うためにディレクトリを作成します。ここでは動作確認用なのでplugiin-testというディレクトリを作成しています。


mac $ mkdir plugiin-test
mac $ cd plugiin-test

npm initコマンドを使ってpackage.jsonファイルの作成を行います。


mac $ npm init -yes

webpackとwebpack-cliのインストールを行います。


mac $ npm install --save-dev webpack webpack-cli

css-loaderとstyle-loaderのインストールを行います。


mac $ npm install css-loader style-loader --save-dev

index.html, index.js , style.cssファイルの作成

index.htmlファイルの作成を行います。distディレクトリはwebpackの設定で指定するディレクトリでその下にwebpackで生成されるbundle.jsファイルを指定します。(現時点ではdistディレクトリは存在しません)


<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>webpack</title>
	<script src="dist/bundle.js"></script>	
</head>
<body>
	<div class="first-header">
		<h1>mini-css-extract-pluginの使い方</h1>
	</div>
</body>
</html>

srcディレクトリの作成を行います。


$ mkdir src

srcディレクトリの下にindex.jsファイルの作成を行います。webpackを実行する際に起点になるファイルで通常はここにJavaScriptのコードを記述しますが、今回はCSSの動作確認なので、CSSファイルの読み込みとconsole.logのみ記述しています。


import './style.css'
console.log('Test');

style.cssファイルを作成します。


.first-header{
	background-color: #FF0000;
	color: #FFFFFF;
	padding: 20px;
}

webpack.config.jsファイルの作成

webpack.config.jsファイルの作成を行います。


$ touch webpack.config.js

const path = require('path')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }, 
  module:{
    rules:[
        {
            test:/\.css$/,
            use:['style-loader','css-loader']
        }       
   ]
  }
}

ここまでの設定で、以下のようなディレクトリ構成になっています。

ディレクトリ構成
ディレクトリ構成

webpackの実行

webpackを実行し、これまでの設定に問題がないか確認を行います。


$ npx webpack

実行後、distディレクトリが自動作成され、bundle.jsファイルが作成されます。ブラウザでindex.htmlを表示すると下記の画面が表示されていれば、問題なく設定が完了しています。

ブラウザで動作確認
ブラウザで動作確認

webpack 4では実行時にmodeの設定がないとWARNINGが表示されます。package.jsonのscriptsに以下を追加して、今後はnpm runコマンドでwebpackを実行させます。


  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack --mode development",
    "build": "webpack --mode production",
    "watch": "webpack --mode development --watch"
  },

mini-css-extract-pluginのインストール

npmコマンドで、mini-css-extract-pluginのインストールを行います。


$ npm install --save-dev mini-css-extract-plugin

インストール完了後、webpack.config.jsにmini-css-extract-loaderの設定に関する記述を追加します。htmlのstyleタグにCSSを埋め込むstyle-loaderは不必要になるため、代わりにmini-css-extract-loaderが追加されます。

Scss Loaderを使用したい場合はcss-loaderの後ろに追加してください。
fukidashi

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }, 
  module:{
    rules:[
        {
            test:/\.css$/,
            use:[
            {
              loader: MiniCssExtractPlugin.loader,
            },
          'css-loader',]
        }      
   ]
  },
  plugins: [
  new MiniCssExtractPlugin({
    filename: 'style.css',
  }),
],
}

webpack.config.jsの更新後、npm run devでwebpackを実行します。実行後、distディレクトリの中にstyle.cssが保存されていることが確認できれば正常に動作しています。

今度は、npm run buildのproductionモードで実行してみましょう。bundle.jsファイルは最小化されていますが、style.cssには何も変化がありません。

下記がbundle.jsファイルの中身です。


!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={

下記がstyle.cssファイルの中身です。


.first-header{
	background-color: #FF0000;
	color: #FFFFFF;
	padding: 20px;
}

webpackでmini-css-extract-pluginを使うことでCSSファイルを別にすることはできましたがPRODUCTIONモードでは最小化されないということがわかりまました。

最小化の問題を解決するためにoptimize-css-assets-webpack-pluginが必要になります。

optimize-css-assets-webpack-pluginのインストール

npmコマンドでoptimize-css-assets-webpack-pluginのインストールを行います。


$ npm install --save-dev optimize-css-assets-webpack-plugin

インストール完了後、webpack.config.jsにoptimize-css-assets-webpack-pluginの設定に関する記述を追加します。pluginsの下のoptimaizationに追加を行っています。


const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }, 
  module:{
    rules:[
        {
            test:/\.css$/,
            use:[
            MiniCssExtractPlugin.loader,
            'css-loader',]
        }      
   ]
  },
  plugins: [
  new MiniCssExtractPlugin({
    filename: 'style.css',
  }),],
  optimization: {
    minimizer: [new OptimizeCSSAssetsPlugin({})],
  },
}

npm run devを実行すると作成されるbundle.jsとstyle.cssに変化はありません。npm run buildのPRODUCTIONモードで実行するとstyle.cssが最小化されていることを確認することができます。


.first-header{background-color:red;color:#fff;padding:20px}

しかし、bundle.jsの最小化が行われなくなっています。

原因は、minimizerにOptimizeCSSAssetsPluginを記述したこでwebpackで初期設定されているJavaScriptの最小化のPluginのTerserの情報が上書きされてしまうためです。そのため、明示的にTerserJSPluginを追加する必要があります。

TeaserJSPluginはwebpackがデフォルト使用するプラグインなので追加インストールは必要ありません。
fukidashi

coconst path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }, 
  module:{
    rules:[
        {
            test:/\.css$/,
            use:[
            MiniCssExtractPlugin.loader,
            'css-loader',]
        }      
   ]
  },
  plugins: [
  new MiniCssExtractPlugin({
    filename: 'style.css',
  }),],
  optimization: {
    minimizer: [new TerserJSPlugin({}),new OptimizeCSSAssetsPlugin({})],
  },
}

追加後、npm run buildを実行するとbundle.jsもstyle.cssも最小化されていることが確認できます。また、npm run devを実行するとbundle.js、style.cssは最小化されない状態で作成されます。

スタイルシートとをJavaScriptファイルと別々に作成し、PRODUCTIONモードではどちらも最小化できることを確認できました。