package.json の browser field 実践編

  • 29
    Like
  • 0
    Comment
More than 1 year has 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の記事 も見てみてください。