目的
requireの引数に変数がある場合に、
webpackはその変数を「全ての文字列」として解釈し、
マッチする全てのファイルをバンドル対象としますが、
その処理を上書きして、一部のファイルのみバンドル対象とするために使います。
使い方
Usageには以下のように定義されています。
2〜4番目の引数(?があるもの)は任意項目のようですが、
JavaScriptにこのような記法があるわけではなく、
自前で引数の型をチェックして、
どの項目が指定されたかどうかを判定しています1。
new webpack.ContextReplacementPlugin(
resourceRegExp: RegExp,
newContentResource?: string,
newContentRecursive?: boolean,
newContentRegExp?: RegExp
)
一番簡単な例として、Moment.jsのロケール設定を置き換えるものが挙げられています。
new webpack.ContextReplacementPlugin(
/moment[\/\\]locale$/,
/de|fr|hu/
)
1番目の引数はresourceRegExp、2番目の引数はnewContentRegExpなのですが、
これをどう指定すればいいのか、
それはMoment.jsのソースコードを読む必要があります。
Moment.js 2.20.1の1844行目あたりに以下のコードがあります。
var aliasedRequire = require;
aliasedRequire('./locale/' + name);
1行目はrequireのaliasを作っているだけなので、問題は2行目です。
どうやらこれをwebpackが解釈する時に、
name変数を任意の文字列にマッチさせています。
ここでは./locale/.*になっていますが、
実際はMoment.jsの内部でのrequireなので、
実ファイルでは、node_modules/moment/locale/.*にマッチします。
このとき、置き換え前のディレクトリはmoment/locale,
マッチする正規表現は.*になっています。
これをそれぞれ、/moment[\/\\]locale$/,
/de|fr|hu/という正規表現に置き換えるのがこのプラグインの目的です。
なお、この/moment/locale$/ でなく /moment[\/\\]locale$/ になっている
理由は、Windows対応のためのようです。
また、newContentRegexpに拡張子がついていないのは、
moduleには拡張子は不要(自動補完される)ためです。