本文書はSocket.ioに記述されているget-startedを参照して作成していますが、クライアント側で行う処理はjqueryではなくvue.jsを利用して行なっています。

Socket.ioの設定がメインになりますが、メッセージの入力や表示に関する箇所はvue.jsを利用しているのでSocket.ioとvue.jsとの組み合わせも理解することができます。

Express.jsのインストールと設定

Express.jsのインストール

npmを使ったJavaScriptのパッケージ管理を行うためnpm initコマンドでpackage.jsonファイルを作成します。


$ npm init -y

npm initの実行フォルダには、package.jsonファイルが作成されます。


$ npm install express

Express.jsの設定

Expressサーバの設定を行います。ポートは3000に設定し、”/”にアクセスがあるとHello Worldを返します。


var app = require('express')();
var server= require('http').Server(app);

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

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

nodeコマンドでサーバを起動します。


$ node index.js

ブラウザからhtpp://locahost:3000にアクセスするとHello Worldが表示されればサーバの初期設定は完了です。

Express.jsでHello World
Express.jsでHello World

HTMLファイルの作成

“/”へのアクセスに対して、Hello Worldの文字列を返していましたが、index.htmlファイルの内容を返すようにルーティングの変更を行います。

htmlファイルの内容を返す場合はsendFileメソッドを利用します。__dirnameは現在更新しているindex.jsファイルが保存されているパスを取得しているので、index.htmlはindex.jsと同じフォルダに作成する必要があります。


app.get('/', function(req, res){
  res.sendFile(__dirname + '/index.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: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>
  </body>
</html>
index.jsのファイルの更新が完了したらnode index.jsを一度終了して再度node index.jsを実行してください。

ブラウザから”/”にアクセスすると以下の画面が表示されます。

簡易チャットの初期画面
簡易チャットの初期画面

Socket.ioのインストール

node installコマンドでsocket.ioのインストールを行います。


 $ npm install socket.io

Socket.ioの基本動作確認

インストールが完了したら、index.jsにsocket.ioに関する行を追加します。読み込んだsocket.ioとhttpサーバオブジェクトを使ってsocket.ioのインスタンスを作成しています。サーバとクライアントでconnectionが発生するとa user connectedがコンソールログに表示されます。


var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server); //追加

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

io.on('connection', function(socket){
  console.log('a user connected'); //追加
});

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

クライアント側になるindex.htmlファイルには以下のsocket.ioのクライアントスクリプトタグを追加します。


<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io();
</script>
io()は引数にURLをとります。URLを入れない場合は、window.locationからURLを取得しています。本環境ではio(‘http://localhost:3000’)と設定しても動作します。

ブラウザでアクセスを行うとサーバとクライアントでConnectionが行われ、サーバ側でa user connectedが表示されます。


$ node index.js
listening on *:3000
a user connected

簡易チャットの構築

簡易チャットを構築するためには、Socket.ioを使ってリアルタイムにサーバ、クライアント間でデータの送受信を行うことを確認する必要があります。まずはクライアントからサーバにメッセージを送ります。

以後サーバとクライアントという言葉が出てきますが、サーバはExpress.jsサーバのことで設定はすべてindex.jsで行います。クライアントはブラウザのことを表し、すべての設定はindex.htmlの中に記述していきます。
リアルタイムとはブラウザでメッセージを送信するとページのリロードを行うことなく、入力したメッセージがすぐにページに反映されることを意味しています。

input要素に入力したデータをサーバに送るためには、input要素に入力したデータを取得する必要があります。vue.jsを使って入力データを取得します。

vue.jsの利用

今回はメッセージを入力する箇所とサーバから送信されてくる各クライアントのメッセージを表示する箇所にvue.jsを利用します。

簡単にvue.jsが使えるvue.jsのcdnを利用します。


<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

クライアントからサーバへのメッセージ送信

入力したメッセージをvue.jsで取得するためにinput要素にv-modelでデータバインディングを行います。入力した値はtextInputプロパティを通してvue.js側で取得することができます。


<input id="m" autocomplete="off" v-model="textInput"/>

button要素にclickイベントを設定します。button要素をクリックするとsendMessageメソッドが実行されます。sendMessageメソッドはvue.jsで準備します。


<button v-on:click="sendMessage">Send</button>

上記の設定を踏まえてvue.jsの設定を行います。


var socket = io();

var app = new Vue({
  el: '#app',
  data: {
    textInput: '',    
  },
  methods:{
    sendMessage : function(e){

      e.preventDefault();

      socket.emit('chat message', this.textInput);

      this.textInput = '';

    }
  }
});

入力したメッセージはSendボタンをクリックするとvue.jsのsendMessageが実行され、textInputプロパティのデータ(=入力したメッッセージ)がsocket.emitメソッドを通して、サーバに送信されます。

送信の際にメッセージを識別するためにイベント名chat messageを設定しています。

サーバのメッセージ受信設定

次に送信したメッセージをサーバ側(index.js)で受信する設定を行います。onメソッドの引数にクライアント側のemitで使用したイベント名chat messageを設定し、メッセージを受け取ったらコンソールログにメッセージを表示させます。


io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    console.log('message: ' + msg);
  });
});

入力フォームにメッセージを入力して、sendボタンをクリックするとサーバ側にそのメッセージが表示されます。

初めてのメッセージ入力
初めてのメッセージ入力

$ node index.js
listening on *:3000
message: はじめてのSocket.ioを使ったメッセージ

サーバからクライアントへのメッセージ送信

クライアントからサーバへメッセージを送信することができたので、次はサーバからクライアントにメッセージの送信を行います。

ここでのクライアントはサーバに接続しているブラウザすべてを表しています。メッセージの送信したブラウザだけでなくメッセージを開かずただサーバに接続しているブラウザも含みます。

先ほどのサーバの受信設定では受け取ったメッセージはconsole.logを使って表示していましたが、今度は受け取ったメッセージをemitメソッドでそのままクライアントに送信します。


io.on('connection', function(socket){
  socket.on('chat message', function(msg){
  	// console.log('message: ' + msg);
    io.emit('chat message', msg);
  });
});

クライアント側での受信設定

クライアント側ではサーバから送られてくるメッセージを受信する必要があります。

メッセージの受信は、サーバと同様にsocket.onメソッドで行うことができます。


var socket = io();

socket.on('chat message',function(msg){
  console.log(msg)
})
メッセージの送信
メッセージの送信
サーバから戻ってきたメッセージがコンソールに表示
サーバから戻ってきたメッセージがコンソールに表示

vue.jsを使ってメッセージをリスト化

クライアントが送信したメッセージを画面上にリスト化するためにvue.jsを利用します。

messagesプロパティを新たに追加し、メッセージをこのmessagesプロパティの中に追加していきます。追加したメッセージをブラウザ上に表示するためにvue.jsのv-forティレクティブを利用します。messagesは配列でメッセージが保持されているので、forによりメッセージ1つ1つを取り出して表示しています。


<ul id="messages">
  <li v-for="message in messages">{{ message }}</li>
</ul>

受け取ったメッセージをmessagesプロパティに追加するためにライフサイクルフックのmountedを利用します。


var socket = io();

var app = new Vue({
  el: '#app',
  data: {
    textInput: '',
    messages: [],  
  },
  methods:{
    sendMessage : function(e){
      e.preventDefault();
      socket.emit('chat message', this.textInput);
      this.textInput = '';
    }
  },
  mounted(){
    socket.on('chat message',function(msg){
      this.messages.push(msg);
    }.bind(this));
  }
});

以上で設定は完了で複数のブラウザを起動してメッセージを入力してみましょう。それぞれのブラウザで入力したメッセージがどちらのブラウザにもリスト化されて表示されます。

ブラウザAでの表示
ブラウザAでの表示
ブラウザBでの表示
ブラウザBでの表示