「npm」と一致するもの

これまでnode.jsのアプリのデプロイにはHerokuを使っていたのですが、 無料アカウントでは上限があるらしいのと、そもそも一つのサービスに依存するのもよろしくないので、別の候補を探しました。

いくつかあるようなのですが、昔は無料でも今は終わっていたり、 今も無料だけどベータサービスなので期限があったりと、 あまりぱっとしません。ビジネスモデルとしてフリーミアムがちゃんと まわってないと持続性がないでしょう。

一番、有望かなと思ったのがRedHatの OpenShift です。

正式サービスしてからはまだ間もないですが、無料のアカウントがサポートなしという形で残っているので、今後も継続することが期待できます。 ただ、無料でホストできるアプリは2つだけのようで、厳しいですが。

さて、 NodeとAngularを使ってTwitterクローンを15分で作るスクリーンキャスト で作ったTwitterクローンをOpenShiftの上にのせることにしました。

まず、OpenShiftのアカウント登録。簡単でした。次に、sshの公開鍵の登録。これもコピペするだけ、簡単。

続いて、アプリの作成。 domainが空いてないと登録できないので、何度もトライしました。 動的にチェックしてくれればいいのに。このあたり、まだまだな感じですね。

続いて、ソースのアップロード。gitのURLが表示されるので、それを、リモートリポジトリとして登録します。

$ git remote add openshift <URL>

で、PUSHします。

$ git push openshift master

ここまで大きな問題なし。このあと大変でした。

まず、今回のアプリはFacebookと連携するのでその情報を入れないといけないのですが、それはリポジトリにはいれるものではありません。 Herokuでは環境変数を使っていました。 openshiftでも環境変数を使えるようで、

$ vi ~/app-root/data/.bash_profile

で追記すれば環境変数を設定できます。 しかし、このままだとnodeを起動するときにその設定は読み込まれないようです。

openshiftにはpre_startというスクリプトがあって、それを使って、 source .bash_profileするようにしたのですが、うまくいきませんでした。

調べているうちに別の方法を見つけました。nodeでしか使えないようなのですが、

$ vi ~/nodejs/configuration/node.env

で環境変数の設定をすることができます。中身は、.bash_profileでの環境変数の設定と同じです。 これは、うまく行きました。

次の問題は、EACCESエラーです。なぜか、webサーバの起動でエラーになるのです。これは、どんぴしゃの記事がありました。

https://www.openshift.com/forums/openshift/other-threads-didnt-help-503-service-unavailable

OpenShiftではINADDR_ANYでlistenできないようです。 app.jsを次のように変えて対処しました。

app.set('port', process.env.OPENSHIFT_NODEJS_PORT || process.env.PORT || 3000);
app.set('ipaddr', process.env.OPENSHIFT_NODEJS_IP);
....
http.createServer(app).listen(app.get('port'), app.get('ipaddr'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

これで、アプリが正常に動作しました。

慣れてしまえば、OpenShiftでもHerokuと同様の使用感でnode.jsのアプリをデプロイできそうです。ただ、困りそうなことが一つだけあります。OpenShiftで用意されているのは、node v0.6なのです。現在の安定版がv0.10なので2世代も前です。Herokuではv0.10もv0.8も使えます。開発スピードが速いnode.jsエコシステムでは致命的かもしれません。npmとかパッケージによっては動かないケースがでてきそうです。

今回は試しませんでしたが、node.jsカートリッジとは別に、DIYカートリッジというのがあるらしく、それを使えば好きなバージョンを入れることができるそうです。そもそも、Herokuではできないsshができるのでいろいろ自由度は高そうですね。

もう一つ、Herokuと比べて不便を感じたのは、デプロイの遅さです。pushしてから待つこと数分かかったような気がします。Herokuってすごいんだなぁ、と思った瞬間。

実際に今回デプロイしたアプリはこちらです。

http://twitterclonesample-nodeangularapp.rhcloud.com/

なんにしてもPaaSの選択肢が増えることはよいことです。 興味ある方は試してみると良いでしょう。


9/10追記。 ~/nodejs/configuration/node.envのファイルですが、いつのまにか勝手に戻っていて、プロセスが8月後半から動いていなかったことが判明しました。とりあえず、再度書いておきましたが、また、勝手に上書きされてしまうかもしれません。もっといい方法があるのでしょうか。

jsdomへのpull request: XHRサポート

  • 投稿日:
  • by

connect-prerendererをちゃんと動かすためにやったjsdomの修正その2をpull requestにしました。

https://github.com/tmpvar/jsdom/pull/654

実はXHR自体は、 node-XMLHttpRequest をそのまま使うだけでほとんど苦労はありませんでした。

大変だったのは、クッキーを引き継ぐところでした。 そもそもXHRを使わない場合も、jsdomはクッキーの引継ぎをサポートしていませんでした。XHRを使わない場合というのは、JavaScriptやCSSや画像ファイルなどを読み込む場合です。

まず、JavaScriptのロード時にもクッキーを引き継ぐようにするコーディングをしてから、XHRでもクッキーを引き継ぐようにしました。XHRはnode-XMLHttpRequestの内部のコードまで理解しなくてはならず、苦労しました。ちょっと強引に実装したため、もしかしたら将来のバージョンのnode-XMLHttpRequestでは動かないかもしれません。

pull requestは無事マージされて、jsdom v0.8.1がリリースされました。興味がある方はお試しください。

https://npmjs.org/package/jsdom

connect-prerenderer もこのバージョンを使うように修正しました。

https://npmjs.org/package/connect-prerenderer

今回は、npm周りのTIPSです。特に新しい知見ではないのですが、メモのために書いておきます。

node.jsのパッケージマネージャであるnpmは依存パッケージの解決をしてくれます。依存パッケージは、package.jsonに書いておきます。

例えば、expressを使う場合、

"dependencies": {
  "express": "*"
}

のように書きます。バージョン番号を指定しておきたい場合もあります。

"dependencies": {
  "express": "3.1.0"
}

のように書きます。他にも不等号やチルダを使ってバージョン番号の範囲を書くこともできます。今回はそのあたりは詳しく書きませんが、package.jsonにはバージョン番号の範囲を書いておくことがおすすめです。node.js関連のパッケージはまだ発展途上で仕様が変わることがよくあるからです。そうでなくても、">=3.0.0"などと書いておけば、"3.0.0"では動いたのだということが分かってよいかもしれません。

さて、本題です。依存パッケージがnpmに登録されていない場合はどうすればよいでしょう? 一つの答えは、登録してしまえばよいのです。が、登録したくない場合もあります。今回そのようなケースがありました。それは、GitHubでforkした場合です。将来的にはPull Requestして取り込んでもらうつもりなら、npmに独自バージョンを登録するのはうまくありません。そこで、npmに登録されていないけれど、依存パッケージとして使いたいときにどうするかという話です。

GitHubを使うとしても方法は2通りあります。一つは、tarballで取得する方法、もう一つは、gitプロトコルで取得する方法です。

前者は、

"dependencies": {
  "jsdom": "https://github.com/dai-shi/jsdom/tarball/3bb5b24c5e"
}

のように書き、後者は、

"dependencies": {
  "jsdom": "git://github.com/dai-shi/jsdom.git#3bb5b24c5e"
}

のように書きます。

どちらがいいのでしょう? よく分かりません。 試しに一回だけ、npm installの時間を計測してみました。 結果、前者が11秒、後者が14秒でした。 gitプロトコルの方がオーバヘッドがあるのかもしれません。 httpプロキシしか使えない場合は、前者に決まりですね。 GitHubがtarballのURLを廃止したら(ZIPのURLはリンクがありますが、tarballってどこまでオフィシャルなのでしょう?)、後者に決まりですね。

今のところはどちらでもよいのかもしれません。


10/20追記。

"https://github.com/dai-shi/jsdom/tarball/3bb5b24c5e"

の代わりに、

"https://github.com/dai-shi/jsdom/archive/3bb5b24c5e.tar.gz"

と書く方法もあるようです。こっちの方がオフィシャルな感じがしますね。

久しぶりにFacebookアプリを作ることにしました。以前作った時から仕様がちょっと変わったので、勉強し直しです。

ちなみに、以前作ったアプリは修正していないので、動かなくなってしまっています。Java & JSPでGAE向けに作ったのであまりやる気が出なくなってしまいました。Node.jsで書き直そうかしらと思いつつも、作り直すならもうちょっと全体設計から見直したいと思って手がつけられていません。

話を戻すと、FacebookのGraph APIを使うためのライブラリを調べました。

http://developers.facebook.com/tools/third-party-sdks/#nodejs

にいくつかリストアップされています。

リポジトリの名前が同じものがあり少しややこしいです。NPMのパッケージ名は違います。Star数が同じなのはたまたまのようです。

さて、少しずつ特徴があります。amachang/facebook-node-sdkとnode-facebook-sdkはオリジナルのFacebook PHP SDKを再現したライブラリになっています。Thuzi/facebook-node-sdkはブラウザ向けのFacebook JavaScript SDKと同じAPIをサーバ側でも実現したものです。これはとてもnode.jsらしいと思いました。fbgraphは、また路線が違ってJavaScriptっぽくJSON APIに書き直したような感じです。

今回はFacebookアプリと言ってもあまり複雑なことをするつもりがなかったのと、以前PHP SDKを見たことがある(そして、わざわざJavaに移植した)ので、PHP SDK互換のものを使おうと思いました。二者択一ならとりあえずStar数を信じてみようということで、amachang/facebook-node-sdkを入れてみました。

ところが、初めに作ったサンプルでつまずきました。applicationのaccess tokenを使ってGraph APIを呼ぶのですが、エラーになるのです。うーん、なぜだ、と思ってソースを眺めると、あれ?application access tokenを取得するAPIが想像していたもの(以前、Rubyのライブラリを使ったことがあった)と違います。こりゃ、動かないわけです。もしかしたら、Facebookの仕様が変わったのかもしれません。深追いするのは止めました。たぶん、user access tokenを使っている範囲では正常なのでしょう。

やはり、Star数の多いものから使おうと、Thuzi/facebook-node-sdkとfbgraphを天秤にかけます。README.mdを読んで比較しました。結果、fbgraphにはapplication access tokenを取得する方法が書いてなく、できるとしてもすっきりしないと予想しました。一方、Thuzi/facebook-node-sdkにはapplication access tokenを取得する方法が書いてありました。application access tokenはサーバ側のコーディングのみで使用可能なため、Facebook JavaScript SDKには入っていないnon-standardな機能です。

作ったサンプルも動作し、満足です。application access tokenを使おうとしている人には参考になるかもしれません。ただし、現時点での話であることをお忘れなく。将来的には状況は変わるかもしれません。

参考までに、コードの抜粋はこちらに。

昨日、見つけてissueの登録をしておいた、connect-offlineの件です。

https://github.com/dustMason/connect-offline/issues/1

早速返事が来ました、Pull Requestにして欲しいと。仕方ないやるかな、と思ってみたものの、やっぱりCoffeeScriptでは書く気になれません。また、パッケージ名も分かりにくいのではないのかと考え、新しく作ることにしました。

初めは、完全互換のパッケージにしようと考えていたのですが、process.cwd()で相対パスを使っているのが気に入らず、__dirnameを使うようにしたかったので、パスの指定の互換性がなくなってしまいました。

作っているうちに他の改善案(ディレクトリの再帰探索)も思いつき、実装方法もだいぶ変わってしまったので、互換の方向性はやめました。とは言っても、基本的には同じように使えるはずです。

https://github.com/dai-shi/connect-cache-manifest

から参照できます。npmにも登録済みです。

express.jsでHTML5のキャッシュマニフェストを使おう考えています。どうせならconnectのmiddlewareにしたら便利だろうと思って調べました。

GitHubでmanifestをキーワードに色々検索したのですが、見つかりませんでした。connect-manifestという空のプロジェクトがあったくらい。

あきらめて、自分で作ろうかと思ったところで、npmで検索してみました。結果、見つけました。

https://github.com/dustMason/connect-offline

offlineという名前だから、GitHubの検索では見つからなかったようです。 Node.jsはパッケージ探しが難しいですね。

このconnect-offlineはStar数が4しかありません。あまり、キャッシュマニフェストをmiddlewareで欲しいと思う人はいないのでしょうか。それとも、名前が悪くてみんな見つけられないのでしょうか。

READMEを読むと、以前のconnectにはcacheManifestというmiddlewareがバンドルされていたようです。connectのリポジトリを探りましたが、確かに、version 1.0より前のタグには存在します。なぜ、やめたのかは分かりませんでした。(消えたファイルのgit logを見ればいいのも)

さて、connect-offlineはちょっと想像していた機能が足りなかったので、自分で修正しようと思ったのですが、ソースがCoffeeScriptだったので手を出しませんでした。(CoffeeScriptはなぜか好きになれないので)

代わりに、issueにしておきました。

https://github.com/dustMason/connect-offline/issues/1