Socket.ioを使って15分でリアルタイムチャットを実装する

Socket.ioのチュートリアルをやったのをまとめました。15分もあればsocket.ioを試すことができます。JavaScriptのコードは20行くらいです。

今回は公式のチュートリアルに沿ってリアルタイムチャット機能の実装を試してみました。
ES6で追加されたアロー関数やconstを使ったりjQueryを使わないで実装をしました。

完成図

![qiita.gif](https://qiita-image-store.s3.amazonaws.com/0/166241/6ec2ef9f-df5b-3f55-e6d8-61a843f598ea.gif)

# Socket.ioに Get Start


- https://socket.io/get-started/chat/

公式をみてみると
> It requires almost no basic prior knowledge of Node.JS or Socket.IO, so it’s ideal for users of all knowledge levels

このチュートリアルは事前知識が全然なくてもできると書いてある(多分)ので初心者でも安心できる。



``` 
mkdir chat-example
cd chat-example
```

以下のようにpackage.jsonを作成する。

``` chat-example/package.json
 { 
    "name": "socket-chat-example", 
    "version": "0.0.1",
    "description": "my first socket.io app",
    "dependencies": {}
}
```


## expressでwebサーバーをたてる


``` 
npm install --save express@4.15.2
 ```


``` index.js
const app = require('express')();
const http = require('http').Server(app);

app.get('/', function(req, res){
  res.send('<h1>Hello world</h1>');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});
```

```
node index.js
```

http://localhost:3000/ にアクセスするとHelloWorldが表示される


[The-web-framework](https://socket.io/get-started/chat/#The-web-framework)


## チャットアプリの雛形を表示してみる

res.sendでHTMLの文字列を渡していたけど、``` sendFile ```メソッドを使うことでhtmlファイルを提供できる。


``` index.js
const app = require('express')();
const http = require('http').Server(app);

app.get('/', function(req, res){
  res.sendFile(__dirname + '/index.html'); //　HTMLファイルを使う
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});
```


今回のチャットアプリのためのHTMLファイル

``` index.html
<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
     * { margin: 0; padding: 0; box-sizing: border-box; }
     body { font: 13px Helvetica, Arial; }
     form { background: #21bace; padding: 6px; position: fixed; bottom: 0; width: 100%; }
     form input { border: 0; padding: 10px; width: 90%; margin-right: 1%; border-radius: 3px;}
     form button { width: 9%; background: white; border: none; padding: 10px; border-radius: 3px; }
     #messages { list-style-type: none; margin: 0; padding: 0; }
     #messages li { font-size: 16px; padding: 10px 15px; }
     #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form id="form">
      <input id="messageField" autocomplete="off" /><button>Send</button>
    </form>
  </body>
</html>
```

http://localhost:3000/ にアクセスするとhtmlファイルが表示されているのがわかる。


## Socket.ioをインストールする


```
npm install --save socket.io
```

``` index.js
const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http);

app.get('/', function(req, res){
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', (socket) => {
  console.log('a user connected');
});

http.listen(3000);
```

bodyタグの閉じタグの前に以下を追加する

``` index.html
<script src="/socket.io/socket.io.js"></script>
 <script>
   const socket = io();
</script>
```

http://localhost:3000/ にアクセスするとコンソールに出力される
別タブで開いても表示される。

```
[xxx:chat-example xxx$ node index.js
a user connected
a user connected
a user connected
a user connected
```


## イベントを送信してみる


emitメソッドを使ってプラウザ側からイベントを送る

``` index.html
<script src="/socket.io/socket.io.js"></script>
 <script>
      document.getElementById('form').addEventListener('submit', (e) => {
        e.preventDefault(); // prevents page reloading
        const messageField = document.getElementById('messageField');
        socket.emit('chat message', messageField.value);
      });
</script>
```



サーバ側でイベントを受診する

``` index.js
io.on('connection', (socket) => {
  socket.on('chat message', (msg) => {
    console.log(msg);
  });
});
```

文字を入力して送信ボタンを押すと、コンソールに入力した文字が出力され、プラウザーサーバー間でのイベントの送受信が正常に行われていることが確認できる。


[Emitting-events](https://socket.io/get-started/chat/#Emitting-events)

## イベントを配信する


あるプラウザからイベントを受診した接続されている全てのプラウザ(ユーザー)に向けてイベントを送信します。

``` index.js
io.on('connection', (socket) => {
  socket.on('chat message', (msg) => {
    io.emit('chat message', msg);
  });
});
```

プラウザ側でイベントを購読する。

``` index.html
<html>
 <body>
   <h1>serve HTML file</h1>
   <script src="/socket.io/socket.io.js"></script>
   <script>
     const socket = io();

     document.getElementById('form').addEventListener('submit', (e) => {
       e.preventDefault(); // prevents page reloading
       const messageField = document.getElementById('messageField');
       socket.emit('chat message', messageField.value);
       messageField.value = '';
     });

     socket.on('chat message', function(msg){
       const item = document.createElement('li')
       item.innerText = msg;
       document.getElementById('messages').appendChild(item);
     });
   </script>
 <body>
</html>
```

[Broadcasting](https://socket.io/get-started/chat/#Broadcasting)


## Socket.ioを使ったチャットアプリのソースコード




``` index.js
const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http);

app.get('/', function(req, res){
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', (socket) => {
  socket.on('chat message', (msg) => {
    io.emit('chat message', msg);
  });
});

http.listen(3000);
```

``` index.html
<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
     * { margin: 0; padding: 0; box-sizing: border-box; }
     body { font: 13px Helvetica, Arial; }
     form { background: #21bace; padding: 6px; position: fixed; bottom: 0; width: 100%; }
     form input { border: 0; padding: 10px; width: 90%; margin-right: 1%; border-radius: 3px;}
     form button { width: 9%; background: white; border: none; padding: 10px; border-radius: 3px; }
     #messages { list-style-type: none; margin: 0; padding: 0; }
     #messages li { font-size: 16px; padding: 10px 15px; }
     #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form id="form">
      <input id="messageField" autocomplete="off" /><button>Send</button>
    </form>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const socket = io();

      document.getElementById('form').addEventListener('submit', (e) => {
        e.preventDefault(); // prevents page reloading
        const messageField = document.getElementById('messageField');
        socket.emit('chat message', messageField.value);
        messageField.value = '';
      });

      socket.on('chat message', function(msg){
        const item = document.createElement('li')
        item.innerText = msg;
        document.getElementById('messages').appendChild(item);
      });
    </script>
  </body>
</html>
```

# Socketを使ってみた感想

この程度のリアルタイムチャット機能を実装するのにJavaScrpt20行程度で済むのは正直驚きました。