ゴールデン・ゲート・ブリッジを渡りながら考えたことのまとめ。
JSXがたくさんの人に使われるようになりました。とてもすばらしいですね。
JSXを使った大規模なコードは次のパターンに分類されると思う。
JSXから、JSXのライブラリを利用
コンパイル結果は、単一の.js。ただし、JSXのライブラリが他のライブラリにさらに依存している可能性あり。
既存のJSコード+JSXラッパー+JSX
コンパイル結果は単一の.jsだけど、依存する.jsコード(もしくは設定ファイルとかもろもろ)がある。
JSXラッパーは既存のJSコードに依存。そのJSコードはさらに他のJSコードに依存?
考えられる組み合わせを網羅する、最小限の複雑なパッケージ依存関係はこんな感じ:
JSXパッケージ awesome_project
+ awesome_projectが依存するJSXパッケージfoo.jsx [1]
| + fooが依存するJSXパッケージbar.jsx [2]
+ awesome_projectが依存するJSパッケージbaz.jsのラッパーbaz.jsx [3]
+ JSパッケージのbaz.js [4]
+ baz.jsが依存するJSパッケージのqua.js [5]
npmじゃなくても、OS非依存なパッケージマネージャであればいけると思うけど、現状、JS系のライブラリを配布する場としてデファクトだと思うので。
node.jsと同じく、現在のスクリプトのある場所 + /node_modules、現在のスクリプトのある場所の親の + /node_modules、その親の・・・とrootまで探索的に決めた場所を順番に探索パスとすることで、[1]と[2]、[3]のケースは簡単に対応できると思う。難しくない。修正するのは、JSXの src/compiler.jsx の Compiler._resolvePath() メソッドでいいのかな。
そのうちC++対応する、という話だけど、C++ではデファクトのパッケージマネージャがないので、面倒を見る必要はないと思う。逆に言えば、ルートのプロジェクトが依存の依存まで全部考慮に入れて頑張るという。まぁ、node_modulesみたいな感じで、includeを探索パスに、libをリンクパスに・・・みたいにするのは手だけど、余計なものを読み込む可能性もあるのでちょっとね。
JSXのみであれば難しくない。コンパイラが探索パスを知っていれさえいれば、最終成果物は1ファイルの実行形式なので怖くない。
問題は、[4]と[5]。全部npmで管理するとしたら、baz.jsとqua.jsはおそらく以下のところにある。
- node_modules/baz.jsx/node_modules/baz/lib/baz.js
- node_modules/baz.jsx/node_modules/baz/node_modules/qua/lib/qua.js
baz.jsxはコンパイルすれば結果ファイルにマージされるが、baz.jsとqua.jsは、実行形式のコードが場所をしる必要がある。 その位置のままで、相対パスのリンクを持つというのも手だけど、それだとコンパイル結果をちょっとコピーしただけでリンクがおかしくなるし、配布者がそんな深い位置にあるファイルまで面倒を見なきゃいけないのは現実的ではないような気がする。qua.jsも、バージョンがあがって、いつのまにかquua.jsというファイルが増えていた!ということもありえる。
実行形式のある場所と同じフォルダ、もしくは一個上位のフォルダのoptだかresourceだかってフォルダを決めて、そこにコピーして、実行ファイルと一緒に配布してね、というのが現実的だと思うけど、どのファイルをコピーするかを管理する方法が今はない。
方法としては2つ。
- jsx.jsonみたいな、メタ情報ファイルを用意して、そいつに記述。package.jsonに書かれた依存プロジェクトのパスを見て、設定を読み込み、必要なファイルをコピー。
- コンパイラに、なんらかの外部依存ファイルを指定するようなディレクティブを追加する。つまりソースコードに書く。
Twitterには後者を書いたけど、あんまり良くない気もしてきた。
という話を、日本に行った時に話をしたけど、.gitリポジトリには、有象無象の複数ファイルが含まれていて、ちょっと粒度が既存のimportよりも大分大きいので、既存のimport文と両立しえるような動作が定義できるのかがいまいちよく理解できてない。ネストされた依存関係の解決も課題かと。submodule?
あと、現状のgitはとりあえずpullしてしまうと過去の情報まで全部とってくるせいで、動作がやたらと重い。JSXを使ってビルドするような実行ファイルを配布する場合、JSXを依存させたとすると、ダウンロードもろもろに結構時間がかかる。jsx --runとかjsx --testを実行するたびに、git fetchして最新ファイルを持ってくるようにするのも重くなるし、コンパイルの動作モードで取得するかどうかを切り替えるなら、npmみたいな別コマンドになっている方が分かりやすいような気もする。