HerokuでExpressとexpress-wsを使ってチャットアプリを動かすサンプル

先日、[Herokuで静的ファイルにNode.js経由 ( Express4.x系 ) でアクセスする時の注意点](http://qiita.com/4243f8278a78e4615d10) という記事を書きました。

その記事で紹介した [y-temp4/heroku-static-provider](https://github.com/y-temp4/heroku-static-provider) を元に、Expressと[express-ws](https://github.com/HenningM/express-ws)を使ったチャットアプリのサンプルを作ってみようと思います。

ソースコードはこちら <i class="fa fa-arrow-right" aria-hidden="true"></i> [y-temp4/express-ws-chat-sample](https://github.com/y-temp4/express-ws-chat-sample)

## express-wsを入れる

まずは[express-ws](https://github.com/HenningM/express-ws)を入れます。

```shell
$ yarn add express-ws
```

`package.json`はこんな感じです。

```json:package.json
{
  "name": "heroku-static-provider",
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "basic-auth-connect": "^1.0.0",
    "compression": "^1.6.2",
    "express": "^4.14.0",
    "express-ws": "^2.0.0",
    "morgan": "^1.7.0",
    "serve-static": "^1.11.1"
  }
}
```

## サーバーの実装

次に、サーバー側を実装します。

```js:server.js
const express     = require('express');
const app         = express();
const expressWs   = require('express-ws')(app);
const morgan      = require('morgan');
const compression = require('compression');
const serveStatic = require('serve-static');
const basicAuth   = require('basic-auth-connect');

const user = process.env.USER;
const pass = process.env.PASS;

let connects = [];

app.set('port', process.env.PORT || 3000);

if (user && pass) {
  app.use(basicAuth(user, pass));
}

app.use(morgan('dev'));
app.use(compression());
app.use(serveStatic(`${__dirname}/public`));

app.ws('/', (ws, req) => {
  connects.push(ws);

  ws.on('message', message => {
    console.log('Received -', message);
    
    connects.forEach(socket => {
      socket.send(message);
    });
  });
  
  ws.on('close', () => {
    connects = connects.filter(conn => {
      return (conn === ws) ? false : true;
    });
  });
});

app.listen(app.get('port'), () => {
  console.log('Server listening on port %s', app.get('port'));
});
```

全員に送信したり、切断時の処理を行うために変数`connects`にて接続状況を管理しています [^1] 。

## クライアントの実装

```js:public/client.js
(function() {
  var HOST = location.origin.replace(/^http/, 'ws');
  var ws = new WebSocket(HOST);
  
  var form = document.querySelector('.form');

  form.onsubmit = function() {
    var input = document.querySelector('.input'); 
    var text = input.value;
    ws.send(text);
    input.value = '';
    input.focus();
    return false;
  }
  
  ws.onmessage = function(msg) {
    var response = msg.data;
    var messageList = document.querySelector('.messages');
    var li = document.createElement('li');
    li.textContent = response;
    messageList.appendChild(li);
  }
}());
```

サーバー側もそうですが、メッセージを送受信するために最低限のことしか書いていません。

## 動作確認

まずはサーバーを起動して、[localhost:3000](http://localhost:3000/)にアクセスします。

```shell
$ node server.js
```

![](https://i.gyazo.com/8c222f405d12f93f733526d2e74e45d5.gif)

左側のブラウザで入力した文字列が右側でも表示できていることが確認できますね。

冒頭にも書きましたが、[y-temp4/express-ws-chat-sample](https://github.com/y-temp4/express-ws-chat-sample)からソースコードを参照できます。Herokuへのデプロイボタンも用意してあるので、実際にHerokuの環境で動かしてみたい方は試してみてください。


以上です。

---


[^1]: 参考：[WebSokectライブラリの「ws」を使ってみた - .blog](http://ishiduca.hatenablog.com/entry/2012/04/20/102437)