Posted at

package.json の browser field 実践編

More than 3 years have passed since last update.


package.json の browser field 実践編

package.json の browser field 入門編 では、package.jsonのbrowser fieldの役割と機能について紹介しました。

本編では、この機能のbundlerごとの実装の違いと、それを回避する方法を説明します。

ここで取り上げる実装の違いとはずばりpathの解決方法です。



  • ./から記述するかどうか


  • .jsを記述するかどうか


  • mainとの対応関係

この3つの要素が絡んできます。

なお、パス解決のresolverを指定できる系もあるようですが、ここでは各々のbundlerがデフォルトで用意しているresolverについて論じています。

(なぜなら、resolverを外部が指定しなければ意図通りbundleされないというのは、利用者にとってはbundleされないのとほぼ同義です)

調査したbundlerは以下です。


パス記述の組み合わせ

組み合わせ的には下記があります



  • ./から記述するかどうか: 変換前と変換後のそれぞれに対して2通り = 4通り


  • .jsを記述するかどうか: 変換前と変換後のそれぞれに対して2通り = 4通り


  • mainの記述方法: 相対パス記述と.js記述のそれぞれで4通り、さらにbrowserフィールドに変換を指定しているか否かで2通り = 8通り

4 x 4 x 8 = 128通りものパターンがあります。

その全パターンについて、指定がうまくいくかどうかを表にしました。


表のよみかた

main
from
to
browserify
webpack
rn-packager

file1
file1
file2
:ok:
:x:
:ok:

1行は、package.jsonと、bundlerごとの解釈結果を示しています。

この行は


package.json

{

"main": "file1",
"browser": {
"file1": "file2"
}
}

という意味です。



  • main カラムはmainフィールドの値


  • from カラムは、browserフィールドの最初のキー


  • to カラムは、fromの値

この場合、webpack以外はうまくバンドルできたということを示しています。


全結果

main
from
to
browserify
webpack
rn-packager

file1
file1
file2
:ok:
:x:
:ok:

file1
file1
./file2
:ok:
:x:
:ok:

file1
file1
file2.js
:ok:
:x:
:ok:

file1
file1
./file2.js
:ok:
:x:
:ok:

file1
./file1
file2
:ok:
:x:
:x:

file1
./file1
./file2
:ok:
:x:
:x:

file1
./file1
file2.js
:ok:
:x:
:x:

file1
./file1
./file2.js
:ok:
:x:
:x:

file1
file1.js
file2
:x:
:x:
:ok:

file1
file1.js
./file2
:x:
:ok:
:ok:

file1
file1.js
file2.js
:x:
:x:
:ok:

file1
file1.js
./file2.js
:x:
:ok:
:ok:

file1
./file1.js
file2
:x:
:x:
:x:

file1
./file1.js
./file2
:x:
:ok:
:x:

file1
./file1.js
file2.js
:x:
:x:
:x:

file1
./file1.js
./file2.js
:x:
:ok:
:x:

./file1
file1
file2
:x:
:x:
:x:

./file1
file1
./file2
:x:
:x:
:x:

./file1
file1
file2.js
:x:
:x:
:x:

./file1
file1
./file2.js
:x:
:x:
:x:

./file1
./file1
file2
:ok:
:x:
:ok:

./file1
./file1
./file2
:ok:
:x:
:ok:

./file1
./file1
file2.js
:ok:
:x:
:ok:

./file1
./file1
./file2.js
:ok:
:x:
:ok:

./file1
file1.js
file2
:x:
:x:
:x:

./file1
file1.js
./file2
:x:
:ok:
:x:

./file1
file1.js
file2.js
:x:
:x:
:x:

./file1
file1.js
./file2.js
:x:
:ok:
:x:

./file1
./file1.js
file2
:x:
:x:
:ok:

./file1
./file1.js
./file2
:x:
:ok:
:ok:

./file1
./file1.js
file2.js
:x:
:x:
:ok:

./file1
./file1.js
./file2.js
:x:
:ok:
:ok:

file1.js
file1
file2
:x:
:x:
:ok:

file1.js
file1
./file2
:x:
:x:
:ok:

file1.js
file1
file2.js
:x:
:x:
:ok:

file1.js
file1
./file2.js
:x:
:x:
:ok:

file1.js
./file1
file2
:x:
:x:
:x:

file1.js
./file1
./file2
:x:
:x:
:x:

file1.js
./file1
file2.js
:x:
:x:
:x:

file1.js
./file1
./file2.js
:x:
:x:
:x:

file1.js
file1.js
file2
:ok:
:x:
:ok:

file1.js
file1.js
./file2
:ok:
:ok:
:ok:

file1.js
file1.js
file2.js
:ok:
:x:
:ok:

file1.js
file1.js
./file2.js
:ok:
:ok:
:ok:

file1.js
./file1.js
file2
:ok:
:x:
:x:

file1.js
./file1.js
./file2
:ok:
:ok:
:x:

file1.js
./file1.js
file2.js
:ok:
:x:
:x:

file1.js
./file1.js
./file2.js
:ok:
:ok:
:x:

./file1.js
file1
file2
:x:
:x:
:x:

./file1.js
file1
./file2
:x:
:x:
:x:

./file1.js
file1
file2.js
:x:
:x:
:x:

./file1.js
file1
./file2.js
:x:
:x:
:x:

./file1.js
./file1
file2
:x:
:x:
:ok:

./file1.js
./file1
./file2
:x:
:x:
:ok:

./file1.js
./file1
file2.js
:x:
:x:
:ok:

./file1.js
./file1
./file2.js
:x:
:x:
:ok:

./file1.js
file1.js
file2
:x:
:x:
:x:

./file1.js
file1.js
./file2
:x:
:ok:
:x:

./file1.js
file1.js
file2.js
:x:
:x:
:x:

./file1.js
file1.js
./file2.js
:x:
:ok:
:x:

./file1.js
./file1.js
file2
:ok:
:x:
:ok:

./file1.js
./file1.js
./file2
:ok:
:ok:
:ok:

./file1.js
./file1.js
file2.js
:ok:
:x:
:ok:

./file1.js
./file1.js
./file2.js
:ok:
:ok:
:ok:

file3
file1
file2
:x:
:x:
:x:

file3
file1
./file2
:x:
:x:
:x:

file3
file1
file2.js
:x:
:x:
:x:

file3
file1
./file2.js
:x:
:x:
:x:

file3
./file1
file2
:x:
:x:
:ok:

file3
./file1
./file2
:ok:
:x:
:ok:

file3
./file1
file2.js
:x:
:x:
:ok:

file3
./file1
./file2.js
:ok:
:x:
:ok:

file3
file1.js
file2
:x:
:x:
:x:

file3
file1.js
./file2
:x:
:ok:
:x:

file3
file1.js
file2.js
:x:
:x:
:x:

file3
file1.js
./file2.js
:x:
:ok:
:x:

file3
./file1.js
file2
:x:
:x:
:ok:

file3
./file1.js
./file2
:x:
:ok:
:ok:

file3
./file1.js
file2.js
:x:
:x:
:ok:

file3
./file1.js
./file2.js
:ok:
:ok:
:ok:

./file3
file1
file2
:x:
:x:
:x:

./file3
file1
./file2
:x:
:x:
:x:

./file3
file1
file2.js
:x:
:x:
:x:

./file3
file1
./file2.js
:x:
:x:
:x:

./file3
./file1
file2
:x:
:x:
:ok:

./file3
./file1
./file2
:ok:
:x:
:ok:

./file3
./file1
file2.js
:x:
:x:
:ok:

./file3
./file1
./file2.js
:ok:
:x:
:ok:

./file3
file1.js
file2
:x:
:x:
:x:

./file3
file1.js
./file2
:x:
:ok:
:x:

./file3
file1.js
file2.js
:x:
:x:
:x:

./file3
file1.js
./file2.js
:x:
:ok:
:x:

./file3
./file1.js
file2
:x:
:x:
:ok:

./file3
./file1.js
./file2
:x:
:ok:
:ok:

./file3
./file1.js
file2.js
:x:
:x:
:ok:

./file3
./file1.js
./file2.js
:ok:
:ok:
:ok:

file3.js
file1
file2
:x:
:x:
:x:

file3.js
file1
./file2
:x:
:x:
:x:

file3.js
file1
file2.js
:x:
:x:
:x:

file3.js
file1
./file2.js
:x:
:x:
:x:

file3.js
./file1
file2
:x:
:x:
:ok:

file3.js
./file1
./file2
:ok:
:x:
:ok:

file3.js
./file1
file2.js
:x:
:x:
:ok:

file3.js
./file1
./file2.js
:ok:
:x:
:ok:

file3.js
file1.js
file2
:x:
:x:
:x:

file3.js
file1.js
./file2
:x:
:ok:
:x:

file3.js
file1.js
file2.js
:x:
:x:
:x:

file3.js
file1.js
./file2.js
:x:
:ok:
:x:

file3.js
./file1.js
file2
:x:
:x:
:ok:

file3.js
./file1.js
./file2
:x:
:ok:
:ok:

file3.js
./file1.js
file2.js
:x:
:x:
:ok:

file3.js
./file1.js
./file2.js
:ok:
:ok:
:ok:

./file3.js
file1
file2
:x:
:x:
:x:

./file3.js
file1
./file2
:x:
:x:
:x:

./file3.js
file1
file2.js
:x:
:x:
:x:

./file3.js
file1
./file2.js
:x:
:x:
:x:

./file3.js
./file1
file2
:x:
:x:
:ok:

./file3.js
./file1
./file2
:ok:
:x:
:ok:

./file3.js
./file1
file2.js
:x:
:x:
:ok:

./file3.js
./file1
./file2.js
:ok:
:x:
:ok:

./file3.js
file1.js
file2
:x:
:x:
:x:

./file3.js
file1.js
./file2
:x:
:ok:
:x:

./file3.js
file1.js
file2.js
:x:
:x:
:x:

./file3.js
file1.js
./file2.js
:x:
:ok:
:x:

./file3.js
./file1.js
file2
:x:
:x:
:ok:

./file3.js
./file1.js
./file2
:x:
:ok:
:ok:

./file3.js
./file1.js
file2.js
:x:
:x:
:ok:

./file3.js
./file1.js
./file2.js
:ok:
:ok:
:ok:


3つとも成功したパターン

main
from
to
browserify
webpack
rn-packager

file1.js
file1.js
./file2
:ok:
:ok:
:ok:

file1.js
file1.js
./file2.js
:ok:
:ok:
:ok:

./file1.js
./file1.js
./file2
:ok:
:ok:
:ok:

./file1.js
./file1.js
./file2.js
:ok:
:ok:
:ok:

file3
./file1.js
./file2.js
:ok:
:ok:
:ok:

./file3
./file1.js
./file2.js
:ok:
:ok:
:ok:

file3.js
./file1.js
./file2.js
:ok:
:ok:
:ok:

./file3.js
./file1.js
./file2.js
:ok:
:ok:
:ok:


導き出された結論



  • to./ で始める必要がある


  • from.js で終わる必要がある


  • from は、それがmainを置き換えるものであるなら、mainと同じ値である必要がある


  • from は、それがmainを置き換えないものであるなら、どんなパターンでもよい


  • from は、mainと同じでない場合は./で始める必要がある


結論を覚えられなかった人へ

全部./.jsをつけよう!mainもね!

mainにだけ付け忘れるとうまくいかないパターンがあるという罠があったわけです。


実験レポジトリ

shinout/bundler-comparison

これをcloneして、自身の手で確認してみてください (要 Node v6)。

Generatorを駆使して組み合わせのループをうまく実装している例にもなっています。

ご参考に。 昔書いたGeneratorの記事 も見てみてください。