2020-05-08

【Node.js】es6以降のSocket.ioサーバーの実装方法

es6以降のimport文を使ってSocket.ioを利用しようとするとエラーになりがち。よく忘れるので実装方法を記す。

Article Image

とりあえずサクっと実装したい人用

次をコピペすればlocalhostport7000で動くはず。

import io from 'socket.io'
const socket = io(7000)

socket.on('connection', function (socket) {
    console.log(`a user connected[id:${socket.id}]`)
    //socket.emit()等の処理はここに記述
})

Socket.io + es6でよく出るエラー

Socket.io(サーバー側)をES6以降のimport文で宣言しようとすると次のエラーに出くわす。

TypeError: socket.on is not a function

これは以前のrequireで宣言していた時の次ようなコード

const PORT = 7000
const io = require('socket.io')(PORT)

これの (PORT) の部分がどういう構文なのか知らずに使っていると

import io from 'socket.io'(PORT) //これはエラー

このような構文は無いので

import io from 'socket.io'

こうしてしまっているからエラーになる。

io = require('socket.io')(PORT)って何?

これは require('socket.io') が「関数」を返しているという点に注意だ。

つまり 関数(PORT)の記述と同義であり'socket.io'から引っ張ってきた関数にPORTを引数で渡してやった結果(このreturn)がioに入っている、ということだ。

私はこの構文の書き方について詳しい説明を見たことがない。

海外のフォーラムでちらっと解説を見かけたことがある程度で恐らく初心者は確実に意味不明だろう。

importで次のコードがなぜエラーになるか

import io from 'socket.io'
io.on('connection', function (socket) { 
...

このコードは冒頭で述べたエラーになる。なぜだろうか?

まず1行目のimportによりioには関数が入っている。

2行目を見て欲しい。io.on() でメソッドが呼ばれている。メソッドが呼べるのはオブジェクト(またはクラス)だけだ。

これを正しいコードに治す

既に冒頭で貼り付けているがもう一度

import io from 'socket.io'
const socket = io(7000)
socket.on('connection', function (socket) {
...

これなら動作する。

これは単純に「ポートを指定したから」という理由ではなく少し内部を理解しておきたい。

先程述べたようにimportした段階でioは関数である。

そしてこのioという関数にポート(の他にオプション等も引数で入れられる)を渡してやって初めてreturnにより使用可能なオブジェクトが帰ってくるという仕組みだ。

これはJavaScriptの構文の勉強でありSocket.ioの動作のクセでもある。

なんとも説明し難い使い方だ。

ちなみに... io じゃなくても良い

import IOOOOOOOOOOOOOOO from 'socket.io'

のように適当な名前にしてもOKだ。

以前はOKじゃなかった気がしたが・・・よくわからんがまぁ動いてるからヨシ!だ(Node.js - v13.12.0)

クライアント側も覚えておく

これでサーバー側は覚えたので、クライアント側もライブラリ名を変えるだけ...と思っているとエラーがでる。

※クライアント用のライブラリは socket.io-client のため別途インストールが必要。

例えば次のコードはエラーだ。

import io from "socket.io-client"
const socket = io(7000)
socket.on("connect", () => {
...

これはこれまでの説明で見れば動きそうに見えるが動かない。

では、どうするのかと言うとioの引数を変更する。

const socket = io("localhost:7000")

クライアント側はURLを設定することになるのでここはポートの数字ではなく文字列で渡す必要がある。

2020/06/16: Vue.jsなら最初はとりあえずこうするという例を記載する

import io from "socket.io-client";
export default {
  name: "HelloWorld",
  data: () => ({
    socket: io("localhost:7000")
  }),
  mounted() { //mountedはアロー関数にしてはいけない
    this.socket.on("connect", () => {
      console.log("connected");
    });
  },
  methods: {}
};

所感

Socket.ioはNode.jsならフロントエンドとの通信に頻繁に利用する(他にもっといい方法があるかもしれないが)ことになるが適当にコーディングしているといつも「あれ、なんでエラー?」と時間を消費するケースが増えたためこの記事を執筆した。

公式はimportに対応している記述があるが、もうすこしes6向けのコードが解説されても良いのではないかと思った。

まだNode.jsではes6以降で書くユーザーは少ないかもしれないが恐らくハマっている人も少なくはないのではないだろうか。



この記事のタグ

この記事をシェア


謎の技術研究部 (謎技研)