Webpackのexternalsについて
webpack 4.19.1 を使っています。
背景
Webpackの設定でexternals
を使うと、指定したモジュールをバンドル対象から外して外部依存のままにできる。
典型的には、ブラウザの<script>
タグで別途CDNからjQueryをロードする前提で、かつソース内でjQueryを
import
していると、webpack実行時にはモジュール解決できずエラーになってしまうが、externals
指定することでエラーを回避できる。
たとえば
/* webpack.config.js */ module.exports = [{ // ... entry: 'main.js', externals: { hoge: 'fuga' }, // ... }]
こんな設定で
/* main.js */ import {app} from 'electron'; import hoge from 'hoge'; // ...
をバンドルすると、hoge
がnode_modules/
とかに存在しなくてもwebpackはエラーにならず、バンドル後のファイルでは単に
module.exports = fuga;
となる。つまり、変数fuga
が定義されていることを前提に、それをhoge
モジュールとして使うようにバンドルしてくれる。
問題
公式ドキュメントを読んだが、いまいちexternals
の書き方がよくわからなかった。
string
、array
, object
、function
、regex
の5通りの記法があるらしい。
string
は上に書いた説明で良さそうだけど、後ろ4つについて理解したい。
結果
まだわかってない部分が多い。何かわかったら追記する...
array
externals: { hoge: ['fuga', 'piyo'] }
と書くと、モジュールの定義は
module.exports = fuga["piyo"];
と出力されていた。定義済みオブジェクトの子孫プロパティをモジュールと見なしたいときに使うと良さそう。
object
正確に言うと、string
の書き方を包含している模様。なのでstring
以外にあたる書き方について。
結論から言うと、どう使うのかよくわからない。
ドキュメント同様
externals : { hoge : { root: ['fuga', 'piyo'] } }
と書くと、module.exports = fuga["piyo"]
になるのだろうと思いきや
module.exports = undefined;
となりまともに実行できないバンドルができる。 ソースを見れば何かわかるのかもしれないが。。
function
これを使うと、ソースでimport
していたモジュールを、バンドルではCommonJS require
されるようにできる模様。
理解できていないけど、
externals: [ function(context, request, callback) { if (request === 'hoge') { return callback(null, 'commonjs ' + request); } callback(); } ]
と設定することで
module.exports = require("hoge");
なるバンドルができる。callback
の第2引数に'commonjs hoge'
を渡している。第1引数は謎。
他にもできることがありそうではある。
実は個人的に一番知りたかったのがこれだった。
2018-09-23 1:00 追記
commonjs
以外に指定できるキーワードには、this
,window
,self
,global
,commonjs2
,amd
,umd
,umd2
がある模様(ソース)callback
の第2引数に'commonjs ' + request
を指定する代わりに、callback(null, request, 'commonjs')
と指定することもできる(ソース)
regex
string
と同様。モジュール名と同名の変数が定義されていることが前提のバンドルができる。
(おまけ)予備調査
Webpackの吐くJSファイルはどんな構造になってるのか、そもそもわかってなかったので少し見た。 きっと設定で変わる部分もありそうだけど、自分の手元で見たものは以下のような感じになっていた。
(function(modules) { // 必要な関数の定義 + エントリポイントの実行 })({ "モジュール1の名前": (function(...) { // モジュール1の定義 }), "モジュール2の名前": (function(...) { // モジュール2の定義 }), // ... });
- 全体は一つの匿名関数の定義となっていて、即時実行される
- その際の引数として、全てのモジュールを持つオブジェクトが渡されている
- エントリポイントもモジュールの一つとして扱われており、匿名関数の末尾でロード(実行)される
という感じ。