トップ «前の日記(2010-11-29) 最新 次の日記(2010-12-01)» 編集

Route 477



2010-11-30

[javascript] パッケージマネージャを備えたサーバサイドJavaScript環境、node.js

node.jsは最近勢いのあるサーバサイドJavaScript環境である。インタプリタにはGoogle ChromeのV8を使用している。

売りとしては「イベント駆動なHTTPサーバが書けるのでCometとかWebSocketのサーバ側に最適」という話なのだが、個人的な用途ではそれは別にRuby+EventMachineとかでいいので、 むしろパッケージマネージャ(npm)を備えたサーバサイドJS環境ができて、JSをRubyとかPerlみたいに使えますよ、という点が面白いと思った。

インストール

port install nodeとか、brew install nodeとか。

パッケージ管理

前述のnpmを入れると、RubyGemsみたいにnpm install fooでパッケージを追加することができる。

モジュール管理

JavaScriptには標準のモジュール管理機構がないが、node.jsはCommonJSという仕様に準拠したモジュール機能を備えている。

定義側が「exports = Foo」、呼び出し側が「var Foo = require('foo')」みたいな感じ。この辺は https://github.com/visionmedia/jade とかの実際のライブラリを見るのが早いかと思う。

ちなみにCommonJSは単にJavaScriptのファイル間の依存関係を指定する方法なので、利用先はnode.jsに限らない。例えばRequireJSというライブラリを使うとブラウザ上でも使用できるようだ。

(追記:CommonJSはモジュールに限らず、さまざまな仕様の共通化を目指しているようだ: http://wiki.commonjs.org/wiki/CommonJS あとnode.jsとRequireJSはAPIが違った)

余談

修論で作ったBiwaTuples(こんな名前だっけか)のサーバ側はGauche+スレッドで書いてたんだけど、むしろnode.jsで実装した方が素直な構成なんじゃないか?と思ったのだった。 素直かどうかはともかく、スレッド使ってたのをイベント駆動で書き直すとどんな感じになるのかはちょっと興味がある。

[javascript] CommonJS準拠の依存関係解決ライブラリについて

もう少し調査した。

まずCommonJSはいくつかの仕様の集まりで、node.jsはModules/1.0を実装していて、 RequireJSはModules/AsynchronousDefinitionを実装しているのでAPIが違ったようだ。

サーバサイド・クライアントサイドの両方で同じAPIを使いたい場合は(という要求がどれくらいあるか分からんが)、 クライアントサイドでModules/1.0が使えるライブラリか、 サーバサイドでModules/AsynchronousDefinitionが使えるライブラリを探せば良いことになる。

CommonJSの準拠実装一覧を見ると、前者にはJSBuildyabbleが、 後者にはnodulesが該当する。

Modules/1.0とModules/AsynchronousDefinitionの違いは、前者がrequire()で後者がdefine()ととりあえず覚えておく(つまりよく分かってない)。

実行効率で言えば、YUI.Compressorとかで1ファイルにコンパイルするのが一番いいんだけど。

追記1

  • 「ライブラリを読み終わってから、HTML内のscriptタグを実行する」みたいな用途はAsyncじゃないと駄目なのかも (全てを*.jsファイルにすればModules/1.0でいいが)
  • node.jsはAsyncの方は非対応なので、サーバ側nodules+クライアント側RequireJSという構成になるか。めんどいな。

ちなみにもっと単純なのでよければ http://labjs.com/documentation.php というのがある。

追記2

  • Asyncな読み込みの方はまだ仕様が固まってなくて、APIがうまく揃わなかった。まだ早いか。
  • productionでは1ファイルにコンパイルする前提なら、クライアント側はLABjsでシーケンシャルに読み込んで、サーバ側ではファイルを直接開いてevalとかで普通にいけそうな気がしてきた。