15 min/d

ぼうずやのにっき

bouzuya/beater の browser support がだめだった

2016-06-09 の続き。bouzuya/beater の browser support を検証した。想定通りにいかず、大幅な見直しが必要になった。

substack/node-browserify / webpack/webpack でいろいろ試したが難しそうな状況だ。beater では test/*.js 相当の file 群を動的に require() するつもりだったが簡単にはいかない。

まず browserify 。

browserify は require() の中身が変数の場合は bundle.js に含めてくれない。類似の issue は substack/node-browserify#377 にある。bundle.js に含まれない点だけであれば substack/bulkify を使えば解決できる。bulkify は glob で bundle.js に含めることはできるが、読み込む時点の制御はできない。

module ごとに require() で読み込まれる module を変更することも意外と難しい。なので file (module name) を渡して、それを require() するのは意外と難しい。独自の browserify transform を用意すれば理論上できそうだけど、利用側での問題が増えそうだ。

次に webpack 。

webpack は browserify の箇所で紹介した issue にもあるが context という考え方を持つ。これは require(expr) / require('pre-' + expr) などの形に応じて directory をわりと乱暴に読み込むものだ。現状の問題としては余計なものを読み込みすぎて死ぬ。'fs''child_process' に依存するものを読み込んでしまう。無理にでもこれを修正してみたが、今度は require() の relative path の指定が思ったようにできず、苦しむ。つくったぼくでこれだ。beater の挙動を知らないと、なぜそんな設定をするのか、どのような path が正解なのか分からないはずだ。

上記に一日費やして、ぼくはひとつ結論に至った。browser で動的な require() を前提にするのは避けるべきだ。ES Modules の観点でも静的解析できるほうが望ましい。

では ES Modules を前提にするとどうなるのか。いまの test() を読み込む時点で実行する構造をとったときは entry point を各 file に置く必要が出てくる。files などの指定ではなくなってしまう。いま考えているのは test()Test の定義として使い、実行の意味を奪う案だ。 const t1 = test(...); export default t1; して Test を export してもらう module をつくれば良い気がしている。考え方は大きく変わるが production code と同じ気持ちで test を書くことができるように思う。

もうすこし考える。