I am trying to convert my code from Nuxt 2 to Nuxt 3, and I have run into an issue with creating a websocket server in Nuxt 3.
It works perfectly fine in Nuxt 2 using this code:
// Nuxt 2: modules/socket.js
import http from 'http'
import socketIO from 'socket.io'
export default function () {
this.nuxt.hook('render:before', () => {
const server = http.createServer(this.nuxt.renderer.app)
const io = socketIO(server)
this.nuxt.server.listen = (port, host) => new Promise(resolve => server.listen(port || 3000, host || 'localhost', resolve))
this.nuxt.hook('close', () => new Promise(server.close))
io.on('connection', (socket) => {
console.log("CONNECTED")
})
})
}
// Nuxt 2: plugins/socket.client.js
import io from 'socket.io-client'
const socket = io('http://localhost:3000')
export default ({}, inject) => {
inject('socket', socket)
}
<!-- Nuxt 2: pages/index.vue -->
<template>
<div>
<p>Check socket status in Vue devtools...</p>
</div>
</template>
<script>
export default {
puted: {
socket() {
return this.$socket ? this.$socket : {};
}
}
}
</script>
However, in Nuxt 3 I cannot access this.nuxt.renderer.app
in the modules/socket.js
file (for http.createServer(...)
), and I cannot figure out how to access the correct renderer.app
elsewhere in a Nuxt3 module. My Nuxt 3 code looks like this:
// Nuxt 3: modules/socket.js
import http from 'http'
import socketIO from 'socket.io'
export default (_, nuxt) => {
// Note that I use the 'ready' hook here - render:before is apparently not included in Nuxt3.
nuxt.hook('ready', renderer => {
// nuxt.renderer is undefined, so I've tried with renderer.app instead, with no luck.
const server = http.createServer(renderer.app)
const io = socketIO(server)
nuxt.server.listen = (port, host) => new Promise(resolve => server.listen(port || 3000, host || 'localhost', resolve))
nuxt.hook('close', () => new Promise(server.close))
io.on('connection', () => {
console.log("CONNECTION")
})
})
}
// Nuxt 3: plugins/socket.client.js
import io from 'socket.io-client'
export default defineNuxtPlugin(() => {
const socket = io('http://localhost:3000')
return {
provide: {
socket: socket
}
}
})
<!-- Nuxt 3: app.vue -->
<template>
<div>
<p>Check socket status in Vue devtools...</p>
</div>
</template>
<script setup>
const { $socket } = useNuxtApp()
</script>
I would make a codesandbox link for you, but every time I try, it breaks before I even add any code. I think it does not correctly work with Nuxt3 yet. Has anyone successfully established a websocket server in a Nuxt 3 module yet? Or can anyone see what I am missing?
I am interested in any working solution, it does not necessarily have to be socket.io
.
I am trying to convert my code from Nuxt 2 to Nuxt 3, and I have run into an issue with creating a websocket server in Nuxt 3.
It works perfectly fine in Nuxt 2 using this code:
// Nuxt 2: modules/socket.js
import http from 'http'
import socketIO from 'socket.io'
export default function () {
this.nuxt.hook('render:before', () => {
const server = http.createServer(this.nuxt.renderer.app)
const io = socketIO(server)
this.nuxt.server.listen = (port, host) => new Promise(resolve => server.listen(port || 3000, host || 'localhost', resolve))
this.nuxt.hook('close', () => new Promise(server.close))
io.on('connection', (socket) => {
console.log("CONNECTED")
})
})
}
// Nuxt 2: plugins/socket.client.js
import io from 'socket.io-client'
const socket = io('http://localhost:3000')
export default ({}, inject) => {
inject('socket', socket)
}
<!-- Nuxt 2: pages/index.vue -->
<template>
<div>
<p>Check socket status in Vue devtools...</p>
</div>
</template>
<script>
export default {
puted: {
socket() {
return this.$socket ? this.$socket : {};
}
}
}
</script>
However, in Nuxt 3 I cannot access this.nuxt.renderer.app
in the modules/socket.js
file (for http.createServer(...)
), and I cannot figure out how to access the correct renderer.app
elsewhere in a Nuxt3 module. My Nuxt 3 code looks like this:
// Nuxt 3: modules/socket.js
import http from 'http'
import socketIO from 'socket.io'
export default (_, nuxt) => {
// Note that I use the 'ready' hook here - render:before is apparently not included in Nuxt3.
nuxt.hook('ready', renderer => {
// nuxt.renderer is undefined, so I've tried with renderer.app instead, with no luck.
const server = http.createServer(renderer.app)
const io = socketIO(server)
nuxt.server.listen = (port, host) => new Promise(resolve => server.listen(port || 3000, host || 'localhost', resolve))
nuxt.hook('close', () => new Promise(server.close))
io.on('connection', () => {
console.log("CONNECTION")
})
})
}
// Nuxt 3: plugins/socket.client.js
import io from 'socket.io-client'
export default defineNuxtPlugin(() => {
const socket = io('http://localhost:3000')
return {
provide: {
socket: socket
}
}
})
<!-- Nuxt 3: app.vue -->
<template>
<div>
<p>Check socket status in Vue devtools...</p>
</div>
</template>
<script setup>
const { $socket } = useNuxtApp()
</script>
I would make a codesandbox link for you, but every time I try, it breaks before I even add any code. I think it does not correctly work with Nuxt3 yet. Has anyone successfully established a websocket server in a Nuxt 3 module yet? Or can anyone see what I am missing?
I am interested in any working solution, it does not necessarily have to be socket.io
.
- I tried to do essentially what you are trying to do in Java a few years ago - I couldn't get handshake to work (apparently you need Berkeley Sockets - developer.mozilla/en-US/docs/Web/API/WebSockets_API/…) the web socket server i am currently using is Ratchet, which I found to be fairly easy to set up and use (especially on Mac/unix) – ControlAltDel Commented Jun 7, 2022 at 16:29
3 Answers
Reset to default 9I figured it out!
Digging deep into the Nuxt 3 code, it turns out that they have a listen
hook which provides the server
parameter that I needed to set up the server. This information is really hard to find though.
I also managed to simplify the script a bit.
Here's the updated modules/socket.js
:
import { Server } from 'socket.io'
export default (_, nuxt) => {
nuxt.hook('listen', server => {
const io = new Server(server)
nuxt.hook('close', () => io.close())
io.on('connection', () => {
console.log("CONNECTION")
})
})
}
Everything else can remain the same
Based on @ahbork's response and a addition from the Nuxt 3 docs, I got this on Vue 3 + Nuxt 3 + Typescript:
import { Server } from 'socket.io'
import { defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('listen', (server) => {
console.log('Socket listen', server.address(), server.eventNames())
const io = new Server(server)
nuxt.hook('close', () => io.close())
io.on('connection', (socket) => {
console.log('Connection', socket.id)
})
io.on('connect', (socket) => {
socket.emit('message', `wele ${socket.id}`)
socket.broadcast.emit('message', `${socket.id} joined`)
socket.on('message', function message(data: any) {
console.log('message received: %s', data)
socket.emit('message', { data })
})
socket.on('disconnecting', () => {
console.log('disconnected', socket.id)
socket.broadcast.emit('message', `${socket.id} left`)
})
})
})
},
})
thx anbork I'm use ws it the same method create file in /modules/wsServer.ts
import { WebSocketServer } from "ws";
import { defineNuxtModule } from "@nuxt/kit";
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook("listen", (server) => {
const wss = new WebSocketServer({ server });
nuxt.hook("close", () => wss.close());
wss.on("connection", (ws) => {
console.log("connection");
ws.on("message", (data) => console.log("received: %s", data));
ws.send("someting");
});
});
},
});
and in page file
let ws;
onMounted(() => {
const wsProtocol = window.location.protocol === "https:" ? "wss:" : "ws:";
ws = new WebSocket(`${wsProtocol}//${window.location.host}`);
ws.onopen = () => console.log("connected");
ws.onmessage = ({ data }: any) => {
console.log("data", data);
};
});
const sendMessage = () => {
ws.send("hello");
};