今回は、Node.jsにExpressのフレームワークとSocket.IOのライブラリをインストールして「チャットアプリ」を作ってみます。
今回は、上記の記事を参考にさせて頂きながらローカルにチャットアプリを作っていきます。
かなり自分への備忘録的な内容が多い記事内容ですが、是非最後までお付き合いいただけたら嬉しいです。
目次
チャットアプリで使用するExpressとSocket.IO
まずはじめに、チャットアプリを作るにあたって使用するフレームワーク「Express」と、ライブラリ「Socket.IO」について学んでおきます。
Express
Expressは、Node.jsのWebアプリケーションフレームワークです。
具体的に「Expressって何なの??」をWikipediaで見てみると、以下の通りです。
Express.js は、サーバーサイドJavaScriptのNode.jsのWebアプリケーションフレームワークである。シングルページ/マルチページ/混在の各種Webアプリケーションの構築のためにデザインされている。
Wikipediaより
ちなみにWebアプリのフレームワークとしては、デファクトスタンダードみたいです。
また、利用しているユーザー数が多いからか、調べたい内容でググっていても検索で引っかかる情報量が多く、日本語での解説記事が多いのも、非常に嬉しいところです。
公式サイト Express
Socket.IO
Socket.IOは、ブラウザとサーバー間の双方向・リアルタイム通信を可能にするライブラリです。
これも同様Wikipediaで見ると以下の通りです。
Socket.IOは、リアルタイムWebアプリケーション用のイベント駆動型ライブラリです。これにより、Webクライアントとサーバー間のリアルタイムの双方向通信が可能になります。
Wikipediaより
今回のチャットアプリでは、「リアルタイムの双方向通信」がチャットが動く時のポイントになるので、このSocket.IOが活躍してくれそうです。
公式サイト Socket.IO
全体の流れ
はじめに、チャットアプリを作ってローカルで動かすまでの全体の流れについておさらいしておきます。
全部で9つのSTEPで完了します。
Node.jsとVS Codeのセットアップをします
ターミナルからディレクトリを作成します。
コードを書いていきチャットアプリを作っていきます。
各ファイルにSocket.IOを組み込みます。
Socket.IOが処理を行えるようコードを追記します。
サーバーを起動して確認します。
完成すると、同時刻にアクセスしているブラウザが連携して、リアルタイムにメッセージが表示されるチャットアプリが出来上がります。
早速やってみましょう。
準備
まずは、Node.jsを使用できるようローカル環境の構築と、VS Codeのインストールを行っていきます。
既にこの2つが完了している方は、この「準備」はスキップして続きをご覧ください。
Node.jsのローカル環境設定
作業で使用するPCに、Node.jsのインストールと環境構築が必要です。
以下は、Node.jsをmacのローカル環境で使う為の構築方法です。こちらの記事を参考にして、設定をしておきましょう。
Node.jsのローカル環境構築で使うターミナルのコマンドまとめターミナルからVSCodeを起動可能にする為の準備
次に、VSCodeをインストールします。
以下公式サイトからダウンロードをして、お使いのデスクトップで使用できるようにしておきましょう。
公式サイト Visual Studio Code
VS Codeは多機能ながらも無料で使えます。
ターミナルでディレクトリを作成
はじめに、ターミナルに以下のコマンドを入力してローカルに chat_app
というディレクトリを作成します。
$ mkdir chat_app
$ cd chat_app
$ npm init -y
作成したディレクトリ内で、最後の行にある npm init
を実行してプロジェクトを初期化して、パッケージインストールの準備を行います。
コマンド入力が完了すると、package.jsonというファイルが同ディレクトリに生成されます。
Expressをインストール
次に、以下のコマンドをターミナルに入力してExpressをインストールします。
npm install express --save
Expressのインストールが完了すると、package.jsonの中の末尾の方に、"dependencies": { "express": "^4.16.4" }
と、Expressの一文が追加されます。
また、app_chat のディレクトリ内は以下のようになってると思います。
これでExpressのインストールは完了です。続けてSocket.IOのインストールを続けましょう。
Socket.IOをインストール
次に、以下のコマンドをターミナルに入力してSocket.IOをインストールします。
npm install socket.io
インストールが完了すると、package.jsonの"dependencies"
にsocket.ioが追加されているはずです。
ここまでで、ExpressとSocket.IOのインストールは完了しました。
以下から、実際にコードを書いてチャットアプリを作っていきます。
コードを書いてチャットアプリの作成
インストールが完了したので、ここからチャットアプリに必要なファイルを作ってコードを書いていきます。
chat_appのディレクトリ内にapp.jsを作成
ExpressとSocket.IOをインストールしたディレクトリ「chat_app」に「app.js」で新規ファイルを作成します。
「app.js」の作成が完了したら、以下のコードを同ファイルに記述します。
// Expressをrequire
const express = require('express')
const app = express()
// ポートは3000番指定
const port = 3000
// ディレクトリでindex.htmlをリク・レス
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
// ポート解放
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
chat_appのディレクトリ内にindex.htmlを作成
次に、chat_appのディレクトリに「index.html」を作成します。
「index.html」ができたら、その中に以下のコードを記述して保存します。
<!DOCTYPE html>
<html>
<head>
<title>チャットアプリをつくってみよう</title>
<style>
* {margin:0; padding:0; box-sizing:border-box; }
body { font-size: 14px; max-width: 600px; width: 100%; margin: 0 auto; padding: 0 15px; }
.chatSend { padding: 3px; position: fixed; bottom: 0; width: 100%; }
.chatText { border: 2px solid #ccc; padding: 10px; width: 90%; margin-right: .5%; border-radius: 5px; }
.sendButton { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; border-radius: 5px; }
#timeline { list-style-type: none; margin: 0; padding: 0; }
#timeline li { padding: 5px 10px; }
#timeline li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<h1>チャットアプリをつくってみよう</h1>
<ul id="timeline"></ul>
<form id="chatSend" action="">
<input id="chatText" autocomplete="off"><button class="sendButton">送信</button>
</form>
</body>
</html>
こうすることで、app.jsで記述したindex.htmlが紐付けされます。
ローカルサーバーを起動して確認
ここまで完了したら、以下のコマンドをターミナルに入力し、ローカルサーバーを起動させてきちんと表示されるか確認してみましょう。
node app
上記のコマンドでローカルサーバーを立ち上げたら、Webブラウザに localhost:3000
を入力し表示させてみます。
起動して上記が画面が表示されていれば、問題なくhtmlファイルが読み込まれています。
ですが、下部のテキストエリアに入力をして送信を押しても何も起きません。ので、一旦 ^C
でサーバーの起動を終了して、Socket.IOを組み込んでいきましょう。
Socket.IOの組み込み
ここまでで、htmlの表示の設定が完了しました。
ここからは、app.jsのファイルにライブラリのSocket.IOを組み込んでリアルタイム通信を可能にしていきます。
app.jsの編集
まずは、「app.js」のファイルを以下のように編集して保存をします。
// Expressをrequire
var app = require('express')();
// httpモジュールをrequire
var http = require('http').Server(app);
var io = require('socket.io')(http);
// ディレクトリでindex.htmlをリク・レス
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
// Socket.IOをコネクト
io.on('connection', function(socket){
console.log('a user connected');
});
// ポートを3000番
http.listen(3000, function(){
console.log('listening on *:3000');
});
編集前のコード、特に冒頭部分の記述が大きく変わります。
index.htmlの編集
そして、index.htmlのファイルに以下のコードを追記します。
コードは <body>〜〜</body>
のクロージングタグ(閉じタグ)前に記述しましょう。
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
記述が完了したら保存をします。
app.jsとindex.htmlにコードを追記
参考記事のように、この時点でローカルサーバーを立ち上げてブラウザで動かしてみても、入力したメッセージは表示されません。
ので、サーバー・クライアントの両方で処理を行えるよう、「app.js」と「index.html」にコードを追加します。
完了まで、あと一息です。
app.jsにコードを追加
app.jsの、編集前 // Socket.IOをコネクト
のコメントが記載されている中に、処理内容を追加します。
編集後のコードは以下のようになります
// Expressをrequire
var app = require('express')();
// httpモジュールをrequire
var http = require('http').Server(app);
var io = require('socket.io')(http);
// ディレクトリでindex.htmlをリク・レス
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
// Socket.IOをコネクト
io.on('connection', function(socket){
console.log('a user connected');
// メッセージ処理
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
// ポートを3000番
http.listen(3000, function(){
console.log('listening on *:3000');
});
こうすることで、io.on
処理に、io.emit('chat message', msg);
を追加して、サーバー側で受け取ったメッセージを全員に発信することが可能になります。
index.htmlにコードを追加
最後に、index.htmlにサーバー側から受け取ったメッセージをブラウザ上へ表示する処理をJavaScriptで追記します。
コードを追記する場所は、<body>〜〜</body>
のクロージングタグ(閉じタグ)前に記述した場所です。
編集後は、以下のコードになります。
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"/>
<title>Chat app</title>
<style>
* {margin:0; padding:0; box-sizing:border-box; }
#chatSec {
width: 100%;
height: 100vh;
display: flex;
align-items: center;
background: #fafafa;
}
.chatBlock {
width: 100%;
max-width: 800px;
margin: 0 auto;
background: #fff;
box-shadow: 0 0 3px 0 rgb(0 0 0 / 12%), 0 2px 3px 0 rgb(0 0 0 / 22%);
transition: 0.2s ease-in-out;
border-radius: 3px;
}
/* 見出し */
.chatBlock h1 {
background: #6bb6ff;
color: #FFF;
padding: 10px 25px;
border-radius: 3px 3px 0 0;
}
/* チャットの中 */
ul#timeline {
padding: 20px 25px;
width: 100%;
height: 400px;
overflow-y: scroll;
flex-direction: column;
display: flex;
gap: 15px;
max-height: 400px;
}
ul#timeline li {
list-style: none;
display: block;
background: #eee;
position: relative;
padding: 12px 15px;
animation: fadeIn 0.7s ease 0s 1 normal;
}
ul#timeline li span {
position: relative;
line-height: 1.4;
display: inline-block;
}
ul#timeline li time {
font-size: 0.7rem;
position: absolute;
right: 8px;
bottom: 5px;
color: #707070;
}
/* 新規チャット */
ul#timeline li:last-child {
background: #e8f3ff;
}
/* フォーム */
form#chatSend {
display: flex;
justify-content: space-between;
padding: 20px 25px;
background: #ecf6ff;
border-radius: 0 0 3px 3px;
}
input#chatText {
line-height: 40px;
border: solid 1px #eee;
background: #FFF;
text-indent: 10px;
font-size: 1.1rem;
display: inline-block;
width: calc(100% - 100px);
}
input#chatText:focus-visible {
outline-color: #6bb6ff;
}
button#sendButton {
width: 90px;
border: none;
background: #6bb6ff;
color: #FFF;
letter-spacing: 0.07rem;
font-weight: 500;
border-radius: 3px;
font-size: 1.03rem;
}
/* アニメーション */
@keyframes fadeIn {
0% {
opacity: 0;
transform: translateY(30px);
}
100% {
opacity: 1;
}
}
</style>
</head>
<body>
<section id="chatSec">
<div class="chatBlock">
<h1>Chat app</h1>
<ul id="timeline"></ul>
<form id="chatSend" action="">
<input id="chatText" autocomplete="off"><button id="sendButton">送信</button>
</form>
</div>
</section>
<script src="/socket.io/socket.io.js"></script>
<script>
let socket = io();
const timeline = document.getElementById("timeline");
const form = document.getElementById("chatSend");
const input = document.getElementById("chatText");
const messages = document.getElementById("sendButton");
form.addEventListener("submit", function (e) {
e.preventDefault();
if (input.value) {
socket.emit("chat message", input.value);
input.value = "";
}
});
socket.on("chat message", function (msg) {
// li タグを生成
let item = document.createElement("li");
// 現在時刻を取得
let posttime = new Date().toLocaleString();
// メッセージと現在時刻をHTMLに挿入
item.innerHTML = '<span>' + msg + '</span><time>' + posttime + '</time>';
// timelineにliタグを挿入してスクロールも追従
timeline.appendChild(item);
timeline.scrollTo(0, timeline.scrollHeight);
});
</script>
</body>
</html>
CSSも追記したのでコード量も増えてます。
io.emit
から発信された情報をsocket.on
で受け取って、ブラウザで表示する処理を行っています。
サーバーを起動して確認
最後に、以下のコマンドでサーバーを再起動して、ブラウザで実際にチャットを動かしてみましょう。
node app
以下のような表示と動作が確認できたら完成です。
動画だと少し小さいですが、各メッセージと投稿時刻が下部に追加で表示されていきます。
メッセージがブラウザに表示されたらOKです!
さいごに
今回、ExpressとSocket.IOで、めちゃめちゃ簡単にチャットアプリを作ることができました。
特にExpressに関しては、Webアプリを作っていく中で頻出しそうなので、より深く学んでいきたいと思います。
参考サイト
参考Node.js入門⑧ Expressフレームワークを使おうプログラミング学習 きくちゃんの勉強部屋