|
| 1 | +--- |
| 2 | +title: How to use with Nuxt |
| 3 | +--- |
| 4 | + |
| 5 | +# How to use with Nuxt |
| 6 | + |
| 7 | +This guide shows how to use Socket.IO within a [Nuxt](https://nuxt.com/) application. |
| 8 | + |
| 9 | +## Server |
| 10 | + |
| 11 | +Under the hood, Nuxt uses [Nitro](https://nitro.unjs.io/) to handle the HTTP requests. |
| 12 | + |
| 13 | +There are two steps to attach a Socket.IO server to a Nitro server: |
| 14 | + |
| 15 | +### Enable WebSockets |
| 16 | + |
| 17 | +WebSockets support in Nitro is currently [experimental](https://github.com/unjs/nitro/issues/2171), so it needs to be manually enabled: |
| 18 | + |
| 19 | +```diff title="nuxt.config.js" |
| 20 | +// https://nuxt.com/docs/api/configuration/nuxt-config |
| 21 | + |
| 22 | +export default defineNuxtConfig({ |
| 23 | + devtools: { |
| 24 | + enabled: true |
| 25 | + }, |
| 26 | ++ nitro: { |
| 27 | ++ experimental: { |
| 28 | ++ websocket: true |
| 29 | ++ }, |
| 30 | ++ } |
| 31 | +}) |
| 32 | +``` |
| 33 | + |
| 34 | +Reference: https://nitro.unjs.io/guide/websocket |
| 35 | + |
| 36 | +### Hook the Socket.IO server |
| 37 | + |
| 38 | +Our Socket.IO server is created in a [Nitro plugin](https://nitro.unjs.io/guide/plugins): |
| 39 | + |
| 40 | +```ts title="server/plugins/socket.io.ts" |
| 41 | +import type { NitroApp } from "nitropack"; |
| 42 | +import { Server as Engine } from "engine.io"; |
| 43 | +import { Server } from "socket.io"; |
| 44 | +import { defineEventHandler } from "h3"; |
| 45 | + |
| 46 | +export default defineNitroPlugin((nitroApp: NitroApp) => { |
| 47 | + const engine = new Engine(); |
| 48 | + const io = new Server(); |
| 49 | + |
| 50 | + io.bind(engine); |
| 51 | + |
| 52 | + io.on("connection", (socket) => { |
| 53 | + // ... |
| 54 | + }); |
| 55 | + |
| 56 | + nitroApp.router.use("/socket.io/", defineEventHandler({ |
| 57 | + handler(event) { |
| 58 | + engine.handleRequest(event.node.req, event.node.res); |
| 59 | + event._handled = true; |
| 60 | + }, |
| 61 | + websocket: { |
| 62 | + open(peer) { |
| 63 | + const nodeContext = peer.ctx.node; |
| 64 | + const req = nodeContext.req; |
| 65 | + |
| 66 | + // @ts-expect-error private method |
| 67 | + engine.prepare(req); |
| 68 | + |
| 69 | + const rawSocket = nodeContext.req.socket; |
| 70 | + const websocket = nodeContext.ws; |
| 71 | + |
| 72 | + // @ts-expect-error private method |
| 73 | + engine.onWebSocket(req, rawSocket, websocket); |
| 74 | + } |
| 75 | + } |
| 76 | + })); |
| 77 | +}); |
| 78 | +``` |
| 79 | + |
| 80 | +And voilà! |
| 81 | + |
| 82 | +## Client |
| 83 | + |
| 84 | +On the client side, all tips from our [Vue 3 guide](/how-to/use-with-vue) are valid. |
| 85 | + |
| 86 | +The only difference is that you need to exclude the Socket.IO client from server-side rendering (SSR): |
| 87 | + |
| 88 | + |
| 89 | +Structure: |
| 90 | + |
| 91 | +``` |
| 92 | +├── components |
| 93 | +│ ├── Connection.client.vue |
| 94 | +│ └── socket.ts |
| 95 | +... |
| 96 | +``` |
| 97 | + |
| 98 | +```js title="components/socket.ts" |
| 99 | +import { io } from "socket.io-client"; |
| 100 | + |
| 101 | +export const socket = io(); |
| 102 | +``` |
| 103 | + |
| 104 | + |
| 105 | + |
| 106 | +```html title="components/Connection.client.vue" |
| 107 | +<script setup> |
| 108 | +import { socket } from "./socket"; |
| 109 | +
|
| 110 | +const isConnected = ref(false); |
| 111 | +const transport = ref("N/A"); |
| 112 | +
|
| 113 | +if (socket.connected) { |
| 114 | + onConnect(); |
| 115 | +} |
| 116 | +
|
| 117 | +function onConnect() { |
| 118 | + isConnected.value = true; |
| 119 | + transport.value = socket.io.engine.transport.name; |
| 120 | +
|
| 121 | + socket.io.engine.on("upgrade", (rawTransport) => { |
| 122 | + transport.value = rawTransport.name; |
| 123 | + }); |
| 124 | +} |
| 125 | +
|
| 126 | +function onDisconnect() { |
| 127 | + isConnected.value = false; |
| 128 | + transport.value = "N/A"; |
| 129 | +} |
| 130 | +
|
| 131 | +socket.on("connect", onConnect); |
| 132 | +socket.on("disconnect", onDisconnect); |
| 133 | +
|
| 134 | +onBeforeUnmount(() => { |
| 135 | + socket.off("connect", onConnect); |
| 136 | + socket.off("disconnect", onDisconnect); |
| 137 | +}); |
| 138 | +
|
| 139 | +</script> |
| 140 | + |
| 141 | +<template> |
| 142 | +<div> |
| 143 | + <p>Status: {{ isConnected ? "connected" : "disconnected" }}</p> |
| 144 | + <p>Transport: {{ transport }}</p> |
| 145 | +</div> |
| 146 | +</template> |
| 147 | + |
| 148 | +``` |
| 149 | + |
| 150 | +:::note |
| 151 | + |
| 152 | +The `.client` suffix in `Connection.client.vue` indicates that the component is meant to be rendered only client-side (no SSR). |
| 153 | + |
| 154 | +Reference: https://nuxt.com/docs/guide/directory-structure/components#client-components |
| 155 | + |
| 156 | +::: |
| 157 | + |
| 158 | +In the example above, the `transport` variable is the low-level transport used to establish the Socket.IO connection, which can be either: |
| 159 | + |
| 160 | +- HTTP long-polling (`"polling"`) |
| 161 | +- [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) (`"websocket"`) |
| 162 | +- [WebTransport](https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API) (`"webtransport"`) |
| 163 | + |
| 164 | +If everything went well, you should see: |
| 165 | + |
| 166 | +``` |
| 167 | +Status: connected |
| 168 | +Transport: websocket |
| 169 | +``` |
| 170 | + |
| 171 | +You can then exchange messages between the Socket.IO server and client with: |
| 172 | + |
| 173 | +- `socket.emit()` to send messages |
| 174 | + |
| 175 | +```js |
| 176 | +socket.emit("hello", "world"); |
| 177 | +``` |
| 178 | + |
| 179 | +- `socket.on()` to receive messages |
| 180 | + |
| 181 | +```js |
| 182 | +socket.on("hello", (value) => { |
| 183 | + // ... |
| 184 | +}); |
| 185 | +``` |
| 186 | + |
| 187 | +That's all folks, thanks for reading! |
| 188 | + |
| 189 | +[Back to the list of examples](/get-started/) |
0 commit comments