GMT猫も杓子もCoffeeScriptの世の中、CoffeeScriptに手を出してしまったがために(JavaScriptの世に)帰らぬ人となりつつある人はたくさんいると思う。僕も最近CoffeeScriptに手を染め五分で帰り途を見失ってしまった。CoffeeScriptの編集にはujihisa氏のshadow.vimが便利だ。開いて編集していると思ったら実はmain.js.shd(中身はCoffeeScript)を編集していて、気づいた時にはすでにmain.js.shdのコンパイル結果がmain.jsに保存されている、というvim-pluginである。JavaScriptを本格的に使うには、モジュールシステムを避けて通る事はできない。グローバル変数を多用することも許されているJavaScriptでは、ライブラリによるオブジェクト空間の汚染は予測できない結果を引き起こしかねない。モジュールシステムは未だ黎明期なので、本稿ではベストのものを選択するよりは、CoffeeScriptで書くクライアントサイド(以下CS)コードをサーバサイド(以下SS)でテストすることを念頭に、モジュールシステムの選び方を検討する、という方向で行こうと思う。ブラウザによる互換性は面倒くさいのでチェックしない。やってることは一緒なのでいざとなれば解決可能な問題だし、各自で使用前にチェックしてください。CommonJSJavaScriptの処理系はちょっとリストアップするのが大変なほどある。これらでばらばらのライブラリAPIを使われてはたまらないので、標準を決めようという事で、CommonJSと呼ばれる標準のようなものがあるらしい。ありがたいことに、CommonJSに参加?しているプロジェクト一覧があり、これをベースに見ていくと楽できそうだ。LoaderRequireJSYabbleSeaJS以下はリストには載ってないが見つけたやつ。bravojsOzJSモジュールシステムについては、Modulesに関係する仕様と提案があり、これを参考にする。Modulesおおまかに言うと、Modules/1.0では以下のようなrequireとexports変数を使ったオブジェクトのエクスポートを要求している。3SSの処理系ではこれは広くサポートされているようだ。(AMD)CSでは、スクリプトの読み込み方法が限られている(scriptタグの追加かXHRによる読み込み)し、同期的読み込みを前提とした上記のような定義方法は実用的ではない。いう名前でいくつかの提案がされている。Modules/Transport/CはModules/AsynchronousDefinition(以下AMD)へと昇格?しているらしい。AMDは以下のような形式で、他のものと比べて暗黙的な変数の導入がなく、スジがよいように思える。これがデファクトになっていくのだろうか。})CoffeeScriptとの相性もよい。これは今回は重要なポイントだ。参考までにCoffeeScript版も書いておく。})といった書き方も用意されているようだ。Loader(partial)backdraftなど。moduleの三つで固定されていることだろうか。その名前から、Modules/1.xとの互換性目的のものと思われる。exportsを使ってもよいし、factory関数の返り値としてオブジェクトを返せばそれがそのままモジュールになる。SeaJSFlyScriptModules/Async/AAMDに対応したローダーの仕様はModules/Async/Aに書かれている。いっても、Yabbleの実装(下記)をそのまま書いてあるだけのような気がするが。対応ライブラリはYabbleのみしか書かれていない...え...結局のところ、AMDはdefineの文法的形式が決まっているだけで、ローダにはまだ決定打がない。コードを書く際はローダの呼び出しを最小限にするのが良さそうだ。この辺がCommonJSの限界のようなので、あとは各々の実装を見ていくのがよさそうだ。});第一引数に依存するモジュールを、第二引数にcallbackを指定する。モジュールのロードが完了すると、callbackが呼ばれる。テストコードも豊富でなかなか完成度の高いコードだ。SSで使われることは想定されておらず、本体に手を入れずに使うことはできなさそう。SSのテストコードでは利用する機能を搾って、同じインターフェースを持つ他のライブラリに丸投げする事が可能だ。main.jsこんな感じで。Nodulesの機能のこれはごく一部で、この他にHTTP上のjsをrequireする(そのためのrequire.ensure)Packages/Mappingsの実装など。コマンドラインからの起動が必要なのはマイナスポイント。あと、defineの第一引数を指定すると、ファイル名(フルパス)と違うと怒られた。RequireJS同じものがRequireJSではこうだ。});シンプルすぎて泣ける。});というように多段にしてrequireすればよい。main.jsとすればいい。この時、engine-nativeのrequire関数はオーバロードされる。この方法だと、CoffeeScript中のrequireなどは置き換えられないため若干使いづらいし、そもそもrequireを汚染されるのは気持ちのいい物ではない。これに関しては、wrapperを書く事で、通常のライブラリと同様読み込むことができるようだ。DojoDojoでは1.6以降AMD形式のライブラリを提供していく予定らしい。Loaderは提供しないので、今回は関係ない。frameworkの中のbdLoadというのがそれらしい。compatibleサイズが小さいのが売りだそうだ。RequireJSのテストコードがレポジトリに含まれていることから、RequireJSのよりよい実装と考えてもよさそうだ。NodeJS用のインターフェースもデフォルトで用意されている。上記RequireJSではwrapperを書いたが、bdLoadではデフォルトでほぼ同じ様になる。...これはかなりいい。RequireJSを選ぶ理由はほぼない気がする。RequireJSはリファレンスマニュアルがかっこいい。ちなみに、backdraftレポジトリをcloneしようとしたら、AAを用いたCAPTCHAのようなものが表示され、フォントが違うので読めなくてログインできない。CAPTCHAは見る価値あり。OzJS作者(dexteryy)はtudou.comのフロントエンジニアらしい。スライドは中国語で詳しくはわからないが、かなり詳細に論じている様子が伺える。他のライブラリに比べると圧倒的にサイズが小さいし、TUICompilerというのを使って静的に複数のスクリプトをまとめることができるようだ。NodeJSからは使えなかった。oz.defしてそっちを使うのがよいかもしれない。})FlyScriptModules/Wrappingsを採用しているFlyScriptだが、何があったのかgithubのレポジトリが消えている。作者の他のレポジトリも丸々ないので公開やめたのかな...SeaJSModules/Wrappingsなのでこんな感じ。})SSでは動かなかった。Backbone.js系のライブラリを添付してくれていて助かるが、必ずmoduleId.jsを読みに行ってしまうみたい。これは、production環境でファイルをまとめたい時などには困るだろう。お手軽にBackbone.jsで遊ぶ専用か。JSLocalnetライセンスがGPLv3/プロプライエタリXHRにしか対応してないIE8非対応コメントがスペイン語レポジトリがhgテストコード一切無しと、異なる文化圏にあるようでちゃんと見るのやめました。またがって共通のモジュールシステムを提供することになるようだ。Modules/2.0提案用のリファレンス実装という色が濃く、unstable感が高いので今回はパス。platform用のAMDローダ。以前まではdojoのローダを使っていたようだが、今はAMDを使うようになったamdブランチがあるようだ。リリースされて一ヶ月とあまり情報もないので見逃していた。non-AMDなjsをロードといった感じ。最後の拡張は、AMD非対応jsが多い現状を考えると面白い。requireの呼び出しはコードの1%にも満たないので、もっとやれ!ということのようだ。*/});サイズCSで利用する際に気になるのはサイズだが各ライブラリの主要ファイルのサイズを以下の方法で調べた。-cOzJSがもっとも小さく、RequireJSが最も大きいがその差は数倍程度の開きでしかなく、あまり大きな要素にはならないように感じた。まとめの項に表を示す。様々なモジュールローダを見て来たが、SS/CSで動くよう作られたライブラリはやはり少なかった。現時点では、SS/CSで使うライブラリをわけるのが選択の幅を狭めない妥協点だ。組み合わせは今回の様な用途を本気で目指したものであり、今後注視しておきたいが、今変化の直中であり手を出しづらい。SeaJS)見受けられ、中国でJavaScriptがキてるのが感じられる。この組み合わせは強そうだ。おまけ名前が挙ってたので調べたけど、関係なさそうなやつ。Teleportteleportは、browserでの開発にNodeJSのエコシステムを持ち込むものらしい。activateとすることで、開発中のpackageにhttp://localhost:4747/PACKAGE_NAME/でアクセスできるようになる。http://localhost:4747/teleport-dashboard/でnpm管理下のパッケージ一覧が見られる。browser上でrequire('...')などとすると、npmパッケージをロードすることができる。形式のモジュールを、defineでくるんでCSに送信する。定義されている場合は、上書きしないような配慮がされている。うまく開発プロセスに組み込めば、ブラウザによるテストも楽になりそう。することで、必要なパッケージを展開?してくれるようだが、これはバグで動かなかった。TransporterTransporterでは、Modules/1.0モジュールを、様々なtransport形式でCSに提供するSSの仕組みを提供している。defineを使うようだが、非同期読み込みには対応しておらず、自分であらかじめscriptタグで読み込んでおく必要があるようだ。