node.jsはじめました

はじめまして! 技術部2年目のsugyanと申します。 初めてtech.kayac.comに投稿します!
先日自分のブログで書いた記事が思いのほか好評だったので、これについてもう少し詳しく書いてみようと思います。
node.js+socket.ioを使ったライブコーディングwebアプリを作ってる - すぎゃーんメモ このエントリーをはてなブックマークに追加

node.jsについて

最近話題の、サーバーサイドJavaScript「node.js」。みなさん触ってみてますか?
Google V8 JavaScript Engineによるイベント駆動の…」と、どんなものかは知っているものの実際には触っていない、という人がまだ多いような気がします。
僕も昨年の12月くらいにようやく触ってみた という程度なのですが、意外にお手軽で簡単に使えるし面白いので、 「JavaScriptはまだニガテで ><」というヒトでも安心して始められるのではと思っています。
せっかくなのでこの機にやってみてはいかがでしょうか!

node.jsのインストール

$ wget http://nodejs.org/dist/node-v0.4.1.tar.gz
$ tar zxvf node-v0.4.1.tar.gz
$ cd node-v0.4.1
$ ./configure --prefix=<インストールしたい場所>
$ make
$ make install
超簡単ですね!PATHが通っていればもうnodeコマンドでプログラムを動かすことができちゃいます。perlやrubyなどのスクリプト言語のようにワンライナーでプログラムを実行することもできます。
$ node -v
v0.4.1
$ node -e 'console.log("Hello World!"); process.exit(0)'
Hello World!

npmでライブラリ管理

アプリ開発にはライブラリが欠かせないですね。 node.js用のライブラリはnpmを使ってインストールするのが便利です。
$ curl http://npmjs.org/install.sh | sh
$ npm install <パッケージ名>
PerlでいうCPANほど熟してはいませんが、数多くのpackageが作成されていてここで公開されています。
node.jsが日々バージョンアップを重ねているため既に動かなくなってしまっているものもありますが、メジャーなライブラリはしっかりメンテナンスされて追従しているので、安心して使えると思います。
せっかくなので幾つかオススメのライブラリを紹介します。
  • Socket.IO
  • Web上でリアルタイムな通信を実現することが出来るライブラリ。WebSocketやxhr-multipart, xhr-pollingなど様々な通信手段をサポートしておりブラウザ間の差異を吸収してくれます。サーバ側もクライアント側も同じようなインターフェースで使えるのも魅力的です。
  • Express
  • Webアプリケーションのためのフレームワーク。簡潔にルーティングが記述でき、多くの機能を備えていて、ある程度のWebアプリを作るには最適だと思います。
  • EJS
  • JavaScript製のテンプレートエンジン。テンプレートエンジンは他にもJadeHamlなど色々あるようですが自分はEJSが一番扱いやすくてお手軽だと思っています。

node.jsでリアルタイムWebアプリを作ろう

では早速、node.jsやsocket.ioを使ってリアルタイムなWebアプリを作ってみましょう。
上記のライブラリたちを使って、下記のようなスクリプト("hello.js"とします)を書きます。
var express = require('express');
var app     = express.createServer();

app.get('/', function(req, res) {
    res.render('index.ejs', {
        layout: false,
        locals: { name: req.param('name') || 'anonymous' }
    });
});
app.listen(3000);
console.log('Server running at http://127.0.0.1:3000/');

var io = require('socket.io');
var socket = io.listen(app);
socket.on('connection', function(client) {
    client.on('message', function(msg) {
        client.send(msg);
        client.broadcast(msg);
    });
})
次に、"views"ディレクトリを作り"views/index.ejs"というファイルを作ります。
<html>
  <head>
    <title>hello node.js!</title>
  </head>
  <body>
    I'm <span id="name"><%= name %></span>.<br />
    <form onsubmit="return send();">
      <input type="text" name="message" id="message" />
      <input type="submit" />
    </form>
    <script type="text/javascript" src="/socket.io/socket.io.js"></script>
    <script type="text/javascript">
      var socket = new io.Socket();
      socket.on('message', function(msg) {
        var div = document.createElement('div');
        div.appendChild(document.createTextNode(msg));
        document.body.appendChild(div);
      });
      socket.connect();

      function send() {
        var message = document.getElementById('message');
        socket.send(document.getElementById('name').innerText + ': ' + message.value);
        message.value = '';
        return false;
      }
    </script>
  </body>
</html>
この2つを書いたら、サーバーを動かして http://localhost:3000/ にブラウザからアクセスしてみましょう。
$ ls -lR
total 8
-rw-r--r--  1 sugyan  staff  519  2 25 02:26 hello.js
drwxr-xr-x  3 sugyan  staff  102  2 25 02:37 views

./views:
total 8
-rw-r--r--  1 sugyan  staff  882  2 25 02:18 index.ejs
$ node hello.js
Server running at http://127.0.0.1:3000/
25 Feb 02:38:34 - Your node instance does not have root privileges. This means that the flash XML policy file will be served inline instead of on port 843. This will slow down initial connections slightly.
25 Feb 02:38:34 - socket.io ready - accepting connections
フォームに文字を入力してsubmitすると、http://localhost:3000/ を開いているすべてのページで画面が更新されます。別タブや別ブラウザなど、複数開きながら見てみると良く分かります。

↑submitした内容が別ブラウザにも即座に反映される!!

簡単な解説

  • サーバ側(hello.js)
  • 最初の約10行は、expressを使って"/"へのリクエストの処理を記述しています。get関数への第1引数がURLのパス、第2引数がリクエストのときのコールバックとなり、これがリクエストとレスポンスを受け取って処理することになります。
    res.renderにviewで使うテンプレートファイル名を指定してやるだけでhtmlの記述はそちらに任せることができます。ここではリクエストで受け取った"name"というパラメータがあればそれを、なければ"anonymous"という文字列をviewに渡すようにしています。
    後半はsocket.ioを使った通信の処理を書いています。client.on("message", function() { .. })でクライアント側から何らかのデータが送られてきた場合の処理を記述しておきます。ここではサーバに繋いでいる他のすべてのクライアントにbroadcastするとともに、自分自身にも同じものを送るようにしています。
  • クライアント側(index.ejs)
  • ejsで書かれたテンプレートは見た目ほぼhtmlと同じですね。<% %>タグでサーバから渡されてきた値を取得したり何らかの処理を記述することができます。
    JavaScriptはsocket.ioのクライアント用ライブラリを読み込んだ後、io.Socketを使用することでサーバ側と同じように通信の処理を書くことが出来ます。こちらはmessageを受け取ったときにページの表示を更新をするように、また、フォームのsubmitが行われたときにその値をサーバに送る(send)ようにしています。

クライアント側を作ってみよう

上の例とはちょっと違いますが似たようなbroadcastサーバをこっそりと動かしています。そこに繋いで同じようなことをするサンプルをjsdo.itにあげてあります。

Socket.IO sample - jsdo.it - share JavaScript, HTML5 and CSS

これも同じように同時に繋いでいるブラウザすべてにリアルタイムに変更が反映されるので、ちょっと工夫すれば簡単にテキストチャットのアプリが作れちゃいますね!
jsdo.itでのSocket.IO使用作品 ←forkして面白いチャットアプリを作ってみませんか!?

いま、リアルタイムwebがアツい!

ライブコーディング!

そういうわけで、このnode.js, socket.ioを使って、web上でライブコーディングするアプリを現在作成中だったりします。
livecoder このエントリーをはてなブックマークに追加
エディタでの編集をリアルタイムに他のユーザの画面に反映させることができるので、これでライブコーディングを行うことができます。
web上でライブコーディングする機能は既にwonderflで実現されていますが、node.js+socket.ioで作ると少なくとも見る側はiPhoneなどでも見えるので魅力的ですね。
いずれjsdo.itにも組み込みたいと思っていますが、まだまだ開発中です。

位置情報共有!

弊社のスマートフォンアプリNakamap(ナカマップ)
自分で更新操作をすることなく、同じグループにいる仲間の位置情報やチャットがどんどんリアルタイムに反映されていきます。

オンライン説明会!

本日2/25(金) 20:00から行われる、弊社のオンライン説明会もリアルタイム技術を駆使しています!
新卒採用企画 オンライン会社説明会 2012 | 面白法人カヤック このエントリーをはてなブックマークに追加
ぜひ見に来てみて下さい!




カヤックではリアルタイム技術が大好きな技術者も募集しています!