ぱろっと・すたじお

技術メモなどをまったりと / my site : http://parrot-studio.com/

CoffeeScriptでNode.jsアプリを書いてみる

すでにCoffeeScriptについてはいろいろ調べていて、
書いてみたりしたこともあったのですが、
Node.js自体はほぼノータッチでした


いろいろすばらしいことはわかっていたものの、
なかなか触る機会がなくて・・・(´-ω-)


皆さんご存じだと思いますが、
「Node.js」は話題のサーバサイドJSの一つです
ちょうど同時期に二大雑誌が特集してます


WEB+DB PRESS Vol.64

WEB+DB PRESS Vol.64

Software Design (ソフトウェア デザイン) 2011年 09月号 [雑誌]

Software Design (ソフトウェア デザイン) 2011年 09月号 [雑誌]


先日、いくつかの偶然*1が重なり、
Node.jsを書いてみよう、ということになったのですが、
やっぱりJavaScriptは書きたくないよね・・・と


というわけで、以下のことを確認してみることに

  • CoffeeScriptだけでNode.jsのコードが全て書けるか?
    • CoffeeScriptはNode.jsで動くのだから、当然のはずだけど、一応
  • モジュールによる構造化が可能か?
    • 一つにファイルに全部のモジュールを書くとか効率が悪すぎる
  • フレームワークの完成度
    • 具体的にはExpress
    • もちろん、全部CoffeeScriptで書けることが前提
  • 外部ライブラリの存在
    • memcachedやMySQLのような、サーバサイドの欠かせないもの


これが全部クリアになれば、「一般的な開発」ができるはず・・・というわけです

Node.jsのインストール


すでにCoffeeScriptを使っていたので、インストール済みではあったのですが、
改めて調べてみることに


元々はMacのHomeBrewでNode.jsを入れてました

brew install node

これでもいいのですが、アップデートが頻繁な技術なので、
rvmのようなバージョン管理がいるだろう、ということで、
「nave」を使ってみました


naveでNode.jsのバージョン管理&イベントループ詳説(1/3)- @IT


この記事の通りにインストールしまして、「nave use latest」をしたところ、
改めてbashのシェルを起動する動作になっており、
profileが適用されなかったので、「nave usemain latest」にしてます


・・・それだと結局、Homebrew経由と変わらんのですが(´・ω・`)

npmのインストール


npmというのはNode.jsのパッケージマネージャーです
RubyのgemとかPerlCPANのようなあれです


これもインストール済みだったのですが、改めてインストール

curl http://npmjs.org/install.sh | sh

最近はこのタイプのインストーラーが多いですね

CoffeeScriptとExpressのインストール


npmからインストールだけ・・・なのですが、
以下の二つは全く違う意味になります

npm install express
npm install -g express

前者はカレントディレクトリのライブラリとして、
後者はグローバルなライブラリとしてインストールされます


具体的には、前者は「./node_modules/express」に一式が、
後者は「/usr/local/lib/node_modules」にライブラリ本体、
「/usr/local/bin」にコマンドが入ります


CoffeeScriptはグローバルに使いたいので・・・

npm install -g coffee-script
npm install -g express

・・・が正解です
Expressもいったんグローバルに入れておきましょう

Expressが吐き出すコードを眺めてみる


Rails同様、Expressもコマンドにより、
基本的なひな形を生成することができます

express exsample # ひな形一式を生成
cd exsample
npm install  # Rubyの "bundle install" に相当
node app.js  # localhost:3000でサーバ起動

まず、「express」コマンドが「rails new」に相当します
引数なしの場合はカレントディレクトリに一式を生成します


次の「npm install」が「bundle install」に相当しますが、
bundleの「Gemfile」のように「package.json」というファイルで、
アプリで使うライブラリが定義されています*2


インストール先はカレントディレクトリの「node_modules」で、
Node.jsがライブラリを探す際、ここを探しにいく仕組みになってます


たいしたコード量ではないので、このひな形をざっと眺めるだけで、
だいたいの構造は見えてくるのですが、
今回の目的はあくまで「CoffeeScriptで書くこと」なので、このままでは使えません

CoffeeScriptでExpressのコードを書く


今回書いたコードはGitHubに置いてあるので、
そちらのhistroyを追ってもらった方が早いのですが、
大雑把にポイントだけ書いてみます


https://github.com/parrot-studio/nodejs-coffee-test


なお、CoffeeScript自体の文法にはノータッチでΣ(゚Д゚)ガーン

最小のコード
# app.coffee
express = require 'express'
app = express.createServer()

app.get '/', (req, res) ->
  res.send 'Hello World!'

app.listen 3000

この5行でサーバが起動し、「Hello Wolrd!」が表示されますΣ(・ω・ノ)ノ

  • 「hoge = require 'piyo'」とすることで、hogeオブジェクトからpiyoモジュールが呼べる
  • 「express.createServer()」がサーバの実体
  • 「app.get [path]」でルーティング
  • 「app.listen [port]」で待ち受ける

本質はこれだけです

外部クラスの呼び出し


ある程度の規模で開発をするのであれば、
クラスを外部から呼び出す・・・くらいのことがしたいです
そこで、それを実現する最小のコードを書いてみました

# comment.coffee
class Comment
  constructor: (@name, @body) ->

  say: -> "#{@name} #{@body}"

exports.Comment = Comment
express = require 'express'
app = express.createServer()
#util = require 'util'

Comment = require('./comment').Comment
com = new Comment 'Hello', 'World!'

#console.log util.inspect com

app.get '/', (req, res) ->
  res.send com.say()

app.listen 3000
  • 「exports」オブジェクトのプロパティとして、functionやクラスを公開する
    • 逆にいえば、ファイル内で使われている他のfunctionはprivateになる、ということ
  • 「require([file])」は、別ファイルのexportsオブジェクトを返す
    • なので、Commentクラスは上記のコードで実体を取り出せる
  • utilパッケージには便利な機能が
    • Rubyの「Object#inspect」に該当するメソッドや、loggingの仕組みなど
その他の話


あとはもう、面倒なんでコードを見てくださいΣ(・ω・ノ)ノ

https://github.com/parrot-studio/nodejs-coffee-test

  • 「memcache」モジュールを経由すればmemcachedとやり取りできる
    • 「package.json」に追記して「npm install」
    • 「JSON.parse」「JSON.stringify」を使えばオブジェクトも格納できる
      • まあ、Rubyでも使っている手段だけど・・・
    • memcachedとのやり取りは非同期なので注意
      • もちろん、そこがNode.jsの肝
  • 「jade」は仕様とExpressの吐くコードを見ればなんとなくわかる
    • http://jade-lang.com/
    • 他のテンプレートエンジンも使えるけど、これがデフォルトなので調べた
  • 「app.configure」あたりは元のapp.jsからそのまま移植しただけなので、細かいとこ見てない
    • 本格的にいじる時にでも調べ直す感じで・・・
  • mysql」モジュールもあった
    • 「memcache」と「mysql」でたいていのアプリはいけそうな・・・

コンパイルと実行


app.coffeeファイルを実行するだけなら、
coffeeコマンドでそのまま実行するだけです

coffee app.coffee

ただ、やはりコンパイルしてJSのコードに変換したいので、
アプリのルートで以下のコマンドを実行する方がベターです

coffee -b -o lib/ -c src/
#coffee -w -b -o lib/ -c src/

後者のように「-w」をつけると、ソースディレクトリを監視して、
更新されたファイルを自動コンパイルしてくれる・・・はずなのですが、
なぜか私の環境では動きませんでした(´・ω・`)


なので、手動で前者コマンドを叩きまくってましたが、
本気で開発するなら原因を突き止めたいところです


コンパイルさえできてしまえば、
「node lib/app.js」で起動できます

まとめ

  • Node.jsを実際に書いてみるとなかなか面白い(`・ω・´) b
    • Expressを使えばいろいろ作れそう
    • 構造化の仕組みも整備されている
    • ライブラリも思ったより多数
  • やっぱりCoffeeScriptは楽
    • Javascript特有の余計なことを考えなくていい


すぐにNode.jsで何か・・・というアイデアはないのですが、
RubyのコードであればCoffeeScriptでほぼそのまま書き直せるので、
何か移植してみると面白そうです


そうなると、「本番環境」特有の問題を考える必要がありますが、
それはまたいつか・・・

*1: システムをリリースして一段落モードだった&Twitterからのトリガー

*2: Gemfileはgemの情報だけを扱ってますが、package.jsonはアプリそのものの情報も扱う点で、微妙に役割が異なりますが、似たようなものです