Nuxt.js + socket.ioでルーム機能付きチャットアプリケーションのサンプル

node.js,Nuxt.js,socket.io

リポジトリ

https://github.com/shoki-kitajima/nuxt-socketio-simple-chat

概要

socket.ioのルーム機能を使って簡単なチャットを作ります。簡単化のため、DBへの永続化はせずチャットデータを持つことはしません。jsが受信したデータをメモリに格納し、ブラウザに描画されたらそれっきりという形です。
Nuxt + socket.ioでさくっと何かを作る時に「どうやるんだっけ」とよくなるのでサンプルを残しておきます。
コンポーネントフレームワークはVuetify.jsを使うこととします。

主に開発環境を用意するのに手間取ることが多いのでその辺りをメインに書きます。

動作確認

docker-compose build
docker-compose up

開発準備

開発環境準備

/docker/nuxt/Dockerfileにある通り、nodeのイメージを利用します。
/docker-compose.ymlも最小限に書いておきます。
この段階でビルドだけしておきます。

Nuxt.jsアプリケーションの作成

Nuxt.js公式が用意してくれているcli、create-nuxt-appを利用します。
公式にも手順があるのでそちらを参考に以下のコマンドを叩いていきます。

なお、今回はcreate-nuxt-appの2系を使用します。

# docker コンテナ内bashを叩く
docker-compose run nuxt bash

# SAOError or fiberのerror防止(2020/07/27エラー確認)にnode-gypをいれる。
# 解決しないようならDockerfileに入れてしまってもよいかも
yarn global add node-gyp

# 3系だとcustom server frameworkが選べないので今回は2.15をいれる。3系を使う場合はserverMiddlewareでExpressを使う
yarn global add create-nuxt-app@2.15.0

# Nuxt.jsのinstall用cliを利用してアプリケーションの雛形を作成
create-nuxt-app

作成時オプションを選べますが、今回は以下の通りに進めます。

? Project name nuxt-socketio-simple-chat
? Project description sample
? Author name 
? Choose programming language JavaScript
? Choose the package manager Yarn
? Choose UI framework Vuetify.js
? Choose custom server framework Express
? Choose Nuxt.js modules 
? Choose linting tools 
? Choose test framework None
? Choose rendering mode Universal (SSR)
? Choose development tools 

これで雛形が作成できました。

# コンテナのbashを終了
exit

# docker-compose起動
docker-compose up

この段階でhttp://localhost:3000/へアクセスするとVuetify+nuxtのwelcomeページが起動されるはずです。

socket.ioのインストール

# 再度コンテナ内bashを叩く
docker-compose run nuxt bash

# socket.ioのインストール
yarn add socket.io
yarn add socket.io-client

socket.io起動処理を書く

server/index.jsをいじります。

server変数を用意しておくのとWebSocketの起動をしておくのを忘れないようにします。

...略
  let server = app.listen(port, host) // あとで使うのでserver変数に格納しておく
...略
  socketStart(server) // 後述のfunctionを実行
...略
  function socketStart(server) { // socket.ioの処理を各場所をまとめておくとよい
  }
... 

いじる際の勘所

コードの部分は実際に書いたものをみてもらえれば。

その他ここさえ分かっていれば大体でかけるよ、という勘所をメモしておく。

  • socket.ioのサーバサイド処理はserver/index.jsに書く
  • client <-> server という感じで相互にイベントのやり取りを定義する
  • room周りが詰まりやすいので、まずjoinができているか、サーバサイドにイベントがemitできているか等泥臭くconsole.logを出しつつデバッグする
  • 間違えがちなのが、ioとsocketのどちら使ってemitするか。その通信にまつわる範囲に収まる場合はsocketでいいが、だいたいio.emit()やio.in().emit()という感じで使うパターンが多いと思う。

あと、socket.io-clientのオブジェクトはrouterでparamとしてページ移動の際に渡すようにしている。新しいインスタンスをバコバコ作るとその分コネクションが増えてしまうと考えているため。

まとめ

さくっと1~2hで作れるだろう、とタカを括っていたら、create-nuxt-appが3系になっていてcustom server frameworkが指定できないところにつまづいた。仕方ないので2系を利用したが、3系でも問題なくExpressを使えるよう。https://github.com/nuxt/create-nuxt-app/issues/563に似たような質問が投げられており、解決策も出ていそう。

加えて、2系のcreate-nuxt-appを実行したところSAOErrorというエラーが出てしまった。3系では問題なかった。なんだろうな、とググってみたところ、nodeのバージョンを上げる等様々な解決策が出てきたが、その中でnode-gypを入れることで解消するかも、というのを試したところ解消された。こういったつまづきが多々あるので、少し前にすぐできたから今回も楽だろう、と環境構築を軽く見積もってはいけない。

双方向通信的なアプリケーションを作る際はfirestore等が候補に入ると思うが、永続化処理が必要ない場合や速度を重視する場合はsocket.ioを使ってみるのもありかと思う。実際に業務でfirestoreを利用した場合とsocket.ioを利用した場合で時間を測ったところ、socket.ioの方が速かった。永続化処理をしていないので当たり前だが。

本当はデザインを整えつつ、初学者向けにしっかり解説をしようと考えていたが、少し時間がかかりそうなのでそれは後回しにする。

node.js,Nuxt.js,socket.io

Posted by shoopon