Help us understand the problem. What is going on with this article?

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の記事 も見てみてください。

shinout
CureAppの中の人。 マルチプラットフォーム、Universal JSのことに関心あり。
https://cureapp.co.jp/
cureapp
医学的エビデンスに基づいた医療機器プログラム『治療アプリ』を開発しています。
https://cureapp.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away