webpack4でスタイルのみをエントリーし、別ファイルとして出力したときに生成される不要なJavaScriptを削除する方法

UI開発者 古川

webpackを静的サイトジェネレーターとして利用するときなどに、Sassなどのスタイルに関するファイルのみをEntry Pointに設定しCSSファイルとして出力すると、スタイルと同じファイル名のJavaScriptが出力されます。このファイルはwebpackの仕様上どうしても生成されてしまうファイルですが、成果物としては不要なものです。また開発環境にHTML Webpack Pluginを導入していた場合、不要なファイルへのファイルパスが自動的に挿入されてしまいます。

今回は不要なJavaScriptを削除し、HTML Webpack Pluginに自動で挿入される不要なJavaScriptへのパスを削除する方法をご紹介します。

問題の解決方法

以降でポイントを解説しますので、まずは全体のソースコードをご覧ください。

const path = require('path');
const globule = require('globule');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const {HtmlWebpackSkipAssetsPlugin} = require('html-webpack-skip-assets-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
// エントリーファイルを動的に取得
const {entries, ignoreFiles} = (() => {
  const entries = {};
  const ignoreFiles = [];

  globule
    .find(['./src/scss/*.scss', '!./src/scss/**/_*.scss'])
    .forEach(filepath => {
      const key = path.basename(filepath, path.extname(filepath));

      ignoreFiles.push(new RegExp(`${key}.js`, 'i'));
      entries[key] = filepath
    });

  return {entries, ignoreFiles};
})();

exports.default = {
  entry: entries,
  mode: 'production',
  module: {
    rules: [{
      test: /\.scss/,
      use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader'
      ]
    }]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      excludeAssets: ignoreFiles
    }),
    new HtmlWebpackSkipAssetsPlugin({
      excludeAssets: ignoreFiles
    }),
    new FixStyleOnlyEntriesPlugin(),
    new MiniCssExtractPlugin({
      filename: '/assets/css/[name].css'
    })
  ],
  resolve: {
    modules: [path.resolve(__dirname, "src"), "node_modules"]
  }
}

不要なファイルを削除する

不要なファイルを削除するにはwebpack-fix-style-only-entriesをPluginsに追加します。

// ...
    plugins: [
        new FixStyleOnlyEntriesPlugin(),
        new MiniCssExtractPlugin({
            filename: '/assets/css/[name].css'
        })
    ],
// ...

今回取り上げた問題を解消するためだけであれば、このプラグインを追加するだけで良いでしょう。

HTML Webpack Pluginに挿入される不要なファイルへのパスを削除する

HTML Webpack Pluginを利用している場合は、生成された不要なファイルへのパスが自動で挿入されます。それを解消するにはHtml Webpack Skip Assets Pluginを利用します。

このプラグインは上記の問題を解決するために開発されていたExclude Assets extension for the HTML Webpack Pluginの互換にあたるプラグインです。Exclude Assets extension for the HTML Webpack Pluginは最新のHTML Webpack Plugin v4.3.0で利用するとエラーで動作しない現象が起きているのですが、開発が止まってしまったようです。

Html Webpack Skip Assets Pluginの使い方は以下のように、HtmlWebpackPlugin()HtmlWebpackSkipAssetsPlugin()のオプションに、excludeAssetsで除外したいファイル名の配列を指定します。ファイル名は正規表現で記述します。

// ...
    plugins: [
        new HtmlWebpackPlugin({
            excludeAssets: [/style.css/]
        }),
        new HtmlWebpackSkipAssetsPlugin({
            excludeAssets: [/style.css/]
        })
    ],
// ...

全体のソースコードでは動的にEntry Pointを生成しているので、その過程で除外したいファイルを取得すれば汎用的に指定が可能です。

まとめ

webpackのEntry Pointに直接スタイルを指定したうえでCSSファイルを出力する手法は、ある意味ではwebpackの本質と離れた使い方になるので依存するプラグインが増えてしまいます。プラグインは便利な反面、開発が止まってしまったり、アップデートによって使えなくなってしまったりすることがあります。

本件のようにwebpackを利用する場合は、そもそも本当にwebpackを用いるべきなのか再考する必要があると感じました。