以前にWebpackでフォルダ内の全ファイルを一気にrequireするという記事(以下、「前記事」とします)を書いたのですが、これでは微妙に気になる点が出てきました。
今回は、その点をクリアするための別な手法を紹介します。
メリットとデメリット
前記事で挙げた、require.context
を使う手法のメリットは、以下のようなものとなります。
- Webpackの標準機能で片付いて、他のライブラリを使う必要がない
- ファイル名もJavaScriptで取得できるので、「
require
した結果をフォルダ構造に従って変数に代入する」というような操作も、そのまま実装できる
一方で、上2つのメリットはそのままデメリットに転じえます。
-
require.context
はWebpack独自仕様なので、Webpackにロックインされてしまう - 「読み込みの副作用だけが必要で、結果は使わない」というような事例を代表として、ファイル名が全く不要な場面でも、ファイル名までバンドルに含まれてしまい、容量を消費する
今回は、後者の「不要なファイル名が容量を消費する」という点が気になったので、改善のために別手法を取ってみることにしました。
globという「共通言語」
Unix系で、複数のファイルを一気に選択するための手法として、ワイルドカードを拡張した「glob」が一般に使われます。そして、このglobを読み込みに使えれば…ということはみんな考えるもので、Browserifyにはrequire-globifyが、Rollupにはrollup-plugin-glob-importがあるなど、各ツールで使えるようになっています。そして、もちろんWebpackにもimport-glob-loaderのようなglob対応ローダーがあります1。
Webpackのimport-glob-loader
は、プレローダーとして仕掛ける、あるいは必要箇所だけimport-glob-loader!./path/to/import.js
のようにして呼び出すこととなります。
module: {
rules: [{
test: /\.js$/,
enforce: "pre",
loader: 'import-glob-loader'
}]
}
注意点
使う上で、いくつか注意点があります。
- 名前の通り、デフォルトでは
import
のみに対応します。設定すればrequire
に反応させられなくもないかもしれませんが、どうなるかはわからないです。 -
import
のある行で、ファイル名以外の部分はすべてコピーされますので、JavaScriptで使う場合は、副作用のみを拾うimport '(glob-pattern).js';
の形以外は事実上使えません(変数名が衝突してしまいます)。 - CSS系の
@import
にも使えます。 - これは
import-glob-loader
に限らないWebpackの挙動だと思われるのですが、import
で書いたものは宣言だからかモジュールの最上部に移動します。ロード順を管理する必要がある場合にimport
とrequire
を混ぜると、思わぬ挙動になりかねないので、そんなことは避けましょう。
実際にやってみた効果
200個ほどrequire
しているものをrequire.context
から移行してみたところ、バンドル全体で90.0KB→88.2KBと、1.8KBほどの削減になりました。