WebSocketをNode.js(Express 4 + EJS + Socket.IO)で復習がてら実装しました。
ハマりポイントはbin/www
を修正しないと動いてくれないところ。
Expressってシンプルで綺麗な設計のフレームワークなんですが、
結構はまりやすいポイントが多いと思います。
Nodeおよびライブラリのバージョン
Node.js 12.14.1 Express 4.16.1 socket.io 2.3.0 EJS 2.6.0
最終成果物
次のと同じものを作る手順を記載します。
ひな形を作成
まずexpress-generator
をグローバルインストールをします。
$ npm install express-generator -g
次にひな形生成をします。いわゆるスキャフォールディングです。 プロジェクトのフォルダはexpress-ws-ejsとします。 テンプレートはEJSを選択します
$ cd express-ws-ejs $ express --ejs
ソースコードを修正
まずsocket.ioを使えるようにします。
$ npm i socket.io --save $ npm i
/models/chat.js
WebSocketのサーバ側です。 新規作成します。modelsフォルダを作り、chat.jsを作成します。
const socketio = require('socket.io'); function chat(server) { const sio = socketio.listen(server); sio.on('connection', function(socket) { socket.on('chat-message', function(msg) { console.log('Send message to client'); sio.emit('chat-message', msg + '💛'); }); socket.on("disconnect", function() { }); }); }; module.exports = chat;
■補足
いくつかあるemitの違い
const sio = socketio.listen(server); sio.on('connection', function(socket) { socket.emit('chat-message', 'message'); // 送信元クライアントだけに送信 socket.broadcast.emit('chat-message', 'message'); // 送信元を除く全クライアントに送信 sio.emit('chat-message', 'message'); // 接続されている全クライアントに送信 }
他にも似たようなのがありますが、これだけ押さえておけばよいでしょう。
javascript - Send response to all clients except sender - Stack Overflow
/bin/www
ここでsocket.ioのlistenをしている/models/chat.jsを呼ばないといけません。
chat.jsはのちほど作成します。
app.jsでこれを呼ぶことはできません。というのもcreateServerをしているのが
/bin/wwwだからだと思われます。
ちなみにですが、var
じゃなくてconst
がいいのですがexpress-generator
がvar
で作るので、
var
のままにしていたりします。
@@ -5,7 +5,8 @@ */ var app = require('../app'); -var debug = require('debug')('express-ws-ejs-o:server'); +var chat = require('../models/chat'); +var debug = require('debug')('express-ws-ejs:server'); var http = require('http'); /** @@ -28,6 +29,7 @@ server.listen(port); server.on('error', onError); server.on('listening', onListening); +chat(server);
/app.js
usersのrouterはいらないので消します
@@ -5,7 +5,6 @@ var logger = require('morgan'); var indexRouter = require('./routes/index'); -var usersRouter = require('./routes/users'); var app = express(); @@ -20,7 +19,6 @@ app.use(express.static(path.join(__dirname, 'public'))); app.use('/', indexRouter); -app.use('/users', usersRouter); // catch 404 and forward to error handler app.use(function(req, res, next) {
/controllers/index.js
これは新規作成します。controllersフォルダを作り、index.jsを作成します。
exports.index = function(req, res) { res.render('index', { title: 'Express' }); }
/routes/index.js
var express = require('express'); var router = express.Router(); var index_controller = require('../controllers/index'); router.get('/', index_controller.index); module.exports = router;
その他リソースおよびview
主にクライアント側です。
Node使ってるとクライアント側なのかサーバ側なのかたまに混乱します。
/public/javascripts/index.js
$(function() { const socket = io('http://localhost:3000'); $('form').submit(function() { console.log($('#m').val()); socket.emit('chat-message', $('#m').val()); $('#m').val(''); return false; }); socket.on('chat-message', function(msg) { $('#messages').append($('<li>').text(msg)); window.scrollTo(0, document.body.scrollHeight); }); });
/public/stylesheets/index.css
* { 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; } #messages { margin-bottom: 40px }
/views/index.js
@@ -2,10 +2,18 @@ <html> <head> <title><%= title %></title> - <link rel='stylesheet' href='/stylesheets/style.css' /> + <link rel='stylesheet' href='/stylesheets/index.css' /> </head> <body> - <h1><%= title %></h1> - <p>Welcome to <%= title %></p> + <ul id="messages"></ul> + <form> + <input id="m" autocomplete="off"> + <button type="submit">Send</button> + </form> + <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script> + <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" + integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8=" + crossorigin="anonymous"></script> + <script src="javascripts/index.js"></script> </body> </html>
Expressの起動
最後にExpressを起動すれば終わりです。
$ npm start
http://localhost:3000 にアクセスし、ブラウザのウィンドウを2つ以上立ち上げると動作確認ができます。
参考
https://socket.io/get-started/chat/
https://liginc.co.jp/web/programming/node-js/132081
https://developer.mozilla.org/ja/docs/Learn/Server-side/Express_Nodejs
https://www.gitignore.io/api/node