WebSocket Support Tracker
Initial PR: https://github.com/unjs/nitro/pull/2170
Relavant docs:
- https://h3.unjs.io/guide/websocket
- https://crossws.unjs.io
Platform support
- [ ] Dev server
- [x] Runtime handlers
- [ ] Dev handlers
- [x]
bun - [x] Cloudflare
- [x]
cloudflare-pages - [x]
cloudflare-module - [x]
cloudflare(worker)
- [x]
- [x] Deno
- [x]
deno-deploy - [x]
deno-server
- [x]
- [ ] Node
- [x]
node-server - [x]
nodeviawebsocketexport - [ ]
node-cluster
- [x]
Needs investigation:
- [ ]
aws-lambda - [ ] AWS amplify
- [ ] Firebase
- [ ] Netlify
- [ ]
netlify-edge - [ ]
netlify-lambda
- [ ]
- [ ]
stormkit - [ ] Vercel
- [ ]
vercel-lambda - [ ]
vercel-edge
- [ ]
- [ ]
wnterjs - [ ]
zerabur
After reviewing the Netlify documentation, I found no suitable offering that will properly support websocket servers at this time.
- Netlify Functions are killed off after 10 seconds. This limit can be increased to 26 seconds if you contact support.
- Netlify Edge-Functions have max 10 seconds of CPU time.
- Netlify Background Functions can run for 15 minutes, but they cannot send a response to the request that triggered them.
Thanks for your investigation. Re Netlify, i have reached out and waiting for an answer if there is any viable current or future plans.
Is websocket still not available in the current development mode of the latest nuxt?
I try to access /websocket in development mode (pnpm run dev) and it's always connecting.
If I compile and start with node .output/server/index.mjs everything works fine.
https://github.com/StringKe/report-nuxt-webscoket
- Operating System: `Darwin`
- Node Version: `v21.5.0`
- Nuxt Version: `3.10.3`
- CLI Version: `3.10.1`
- Nitro Version: `2.9.3`
- Package Manager: `[email protected]`
- Builder: `-`
- User Config: `nitro`
- Runtime Modules: `-`
- Build Modules: `-`
@StringKe You need to use nuxi-nightly.
Are there plans to let us define which adapters defineWebsocketHandler uses internally?
Specifically, in my case I want to use the crossws uWs adapter
https://github.com/unjs/nitro/pull/2170/files#diff-874de70a2b8dc27aa6a857ee5110f1b1ab675afc9e6b1191bebfb1119ad7c78fR7
Or is it possible to just import it manually and use it instead of defineWebsocketHandler?
uws requires it's own server preset for Nitro to be supported. (because it is not based on node:http)
does crossws have an API to proactively close connection?
Does nuxt support websocket when deployed on cloudflare pages? Everything is fine on localhost, but on Cloudflare I'm getting only status finished
Hello, I am trying to combine peer-server with my Nuxt application. Unfortunately, it doesn't work as expected. The reproduced issue is in nuxt/nuxt
In the peer-server middleware, ws is used to send the WebSocket message
https://github.com/peers/peerjs-server/blob/master/src/services/webSocketServer/index.ts#L59
import { WebSocketServer as Server } from "ws";
const options: WebSocket.ServerOptions = {
path: this.path,
server,
};
this.socketServer = new Server(options);
this.socketServer.on("connection", (socket, req) => {
this._onSocketConnection(socket, req);
});
Currently, Nuxt is unable to listen for web socket connection events as expected
Does nuxt support websocket when deployed on cloudflare pages? Everything is fine on localhost, but on Cloudflare I'm getting only status finished
Hi did u manage to get this fixed?
Thanks for your investigation. Re Netlify, i have reached out and waiting for an answer if there is any viable current or future plans.
Hi, @pi0 any updates on this from the netlify team?
For netlify, you might use SSE (long polling) as much as know. @serhalp might give better answer if there is any plans for future WebSocket API.
👋🏼 I'm not aware of any plans to change Netlify's support for WebSockets. However, Server-Sent Events (SSE) work great with Netlify Edge Functions.
@pi0 is there an example somewhere that instructs how to set up websockets with the cloudflare-module Nitro preset?
When using the example from the docs, if I run locally in Nuxt (via nuxt dev) the tabs communicate properly; however, when I build and then run wrangler dev there is no communication between separate tabs.
I can see each peer is available (the number is incremented for each connected client if I output on the page) but I can not receive messages between them after calling subscribe/publish accordingly.
I see the following note on the CrossWS Pub / Sub page:
Native pub/sub is currently only available for Bun, Node.js (uWebSockets) and Cloudflare (durable objects)
but there are no instructions as to how to actually hook it up (here in the Nitro docs) to Cloudflare Durable Objects?
If you can point me in the right direction I can also push up a PR for docs.
Alternatively, if you have another (non-experimental) suggestion on how to implement similar messaging, I'd be open to try.
Durable-ojbect support is on the progress (sorry for misleading docs, that section is not released yet)
Durable-ojbect support is on the progress (sorry for misleading docs, that section is not released yet)
😅 Well I feel better that I couldn't get it working now. Tag me if I can help test/implement/document
Hello, is there a way to access the event similar to defineEventHandler or eventHandler in Nuxt? I'm asking because I'm trying to retrieve a router parameter, and all server utility functions require the event parameter.
Hello, is there a way to access the event similar to defineEventHandler or eventHandler in Nuxt? I'm asking because I'm trying to retrieve a router parameter, and all server utility functions require the event parameter.
A route parameter from the websocket route? what's your use case?
I'm trying to create a proxy for Parse Server's LiveQueries and need to pass parameters to initialize the SDK and perform the necessary queries. I'm not sure if this is the best approach, as I'm just starting out with WebSockets.
Yeah, if it possible, please: add possibility to read params from url. It's might be useful to authenticate user with one-time/signed token.
Possible solution may be second (or first, ws still experimental feature anyway) argument to open() hook
UPD:
it's possible to parse params from peer.url string:
export default defineWebSocketHandler({
open(peer) {
console.log(peer.url); // `/some/usr/TOKEN/ws`
},
});
What about platforms not mentioned, (e.g. Azure) are they omitted for any reason?
@pi0 is there an example somewhere that instructs how to set up websockets with the
cloudflare-moduleNitro preset?When using the example from the docs, if I run locally in Nuxt (via
nuxt dev) the tabs communicate properly; however, when I build and then runwrangler devthere is no communication between separate tabs.I can see each
peeris available (the number is incremented for each connected client if I output on the page) but I can not receive messages between them after callingsubscribe/publishaccordingly.I see the following note on the
CrossWS Pub / Subpage:Native pub/sub is currently only available for Bun, Node.js (uWebSockets) and Cloudflare (durable objects)
but there are no instructions as to how to actually hook it up (here in the Nitro docs) to Cloudflare Durable Objects?
If you can point me in the right direction I can also push up a PR for docs.
Alternatively, if you have another (non-experimental) suggestion on how to implement similar messaging, I'd be open to try.
hey, currently i'm also facing the same issue, connections works pretty well in local dev nuxt dev. However can't see incoming data when running with wrangler dev. Any lead on this ?
@pi0Existe algum exemplo em algum lugar que instrua como configurar websockets com a
cloudflare-modulepredefinição Nitro? Ao usar o exemplo da documentação , se eu executar localmente no Nuxt (vianuxt dev), as guias se comunicam corretamente; no entanto, quando eu compilo e executo,wrangler devnão há comunicação entre guias separadas. Posso ver que cada umpeerestá disponível (o número é incrementado para cada cliente conectado se eu exibir na página), mas não consigo receber mensagens entre eles depois de fazer a chamadasubscribe/publishcorrespondente. Vejo a seguinte nota naCrossWS Pub / Subpágina :O pub/sub nativo está disponível atualmente apenas para Bun , Node.js (uWebSockets) e Cloudflare (objetos duráveis)
mas não há instruções sobre como conectá-lo (aqui nos documentos do Nitro) aos Objetos Duráveis do Cloudflare? Se você puder me indicar a direção certa, também posso aumentar o PR dos documentos. Alternativamente, se você tiver outra sugestão (não experimental) sobre como implementar mensagens semelhantes, eu estaria aberto a tentar.
ei, atualmente também estou enfrentando o mesmo problema, as conexões funcionam muito bem no dev local
nuxt dev. No entanto, não consigo ver os dados de entrada ao executar comwrangler dev. Alguma pista sobre isso?
Any news ?
Just tried using this feature in node with nuxt, it seems ws doesn't support sending messages asynchronously.
WS Implementation
export default defineWebSocketHandler({
open(peer) {
ready("Connected to peer: ", peer.id);
},
async message(peer, message) {
const config = useRuntimeConfig();
if (message.text() === "get-data") {
await $fetch(`${config.public.apiBaseUrl}/frontend-counters`).then(
peer.send,
);
}
},
close(peer, event) {
info(`Peer \`(${peer.id})\` disconnected. Reason: ${event.code}`);
},
error(peer, error) {
fail("An error occured: ", peer.id, error);
},
});
I keep getting this error in preview server
[unhandledRejection] TypeError: Cannot read properties of undefined (reading '_internal')
at send (.output/server/chunks/nitro/nitro.mjs:5266:10)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async message (.output/server/chunks/routes/api/websocket.mjs:33:7)
ℹ Peer (331f477a-20ca-4ecc-adf7-1ad37d96448e) disconnected. Reason: 1000 server:ws 9:45:24 AM
[unhandledRejection] TypeError: Cannot read properties of undefined (reading '_internal')
at send (.output/server/chunks/nitro/nitro.mjs:5266:10)
And some times the dev server doesn't start
Meta
The preview server is node-server, on a mac, with node v20.19 (also tested on node 22)
@splitwarechef Please consider sharing a minimal reproduction with nitro 🙏🏼
See here: https://stackblitz.com/~/github.com/splitwarechef/test-nitro-websocket
Absolute paths don't work on stackblitz so I suggest you try this on your local instead.
Edit
The github repo is public, you're free to clone
Thanks for reproduction @splitwarechef 🙏🏼 (please consider using nitro only reproductions in the future not nuxt and also use new issues )
Issue is that you are calling peer method with wrong context:
--- await $fetch(`/api/counter`).then(peer.send);
+++ await $fetch(`/api/counter`).then(message => peer.send(message));
Any idea when the cloudflare-durable preset might be ready for production (and docs)? I'd love to cook something up in my production app 👨🏼🍳
Thanks for reproduction @splitwarechef 🙏🏼 (please consider using nitro only reproductions in the future not nuxt and also use new issues )
Issue is that you are calling peer method with wrong context:
--- await $fetch(
/api/counter).then(peer.send); +++ await $fetch(/api/counter).then(message => peer.send(message));
Thank you @pi0. Also, noted!.
Not exactly standard, but I'm using a bastardized version in server middleware to wrap the nuxt node server to create a Websocket that can be integrated with trpc. I was wondering if there were any plans to be able to let us define the server it uses e.g. if I want to switch completely to uwebsockets etc and integrate with the trpc uwebsockets package, just throwing this out there in case there are other options I'm not aware of
import type { CreateWSSContextFnOptions } from "@trpc/server/adapters/ws";
import type { Server } from "node:http";
import { getSynchronizedFunction } from "#shared/util/getSynchronizedFunction";
import { createCallerFactory } from "@@/server/trpc";
import { createContext } from "@@/server/trpc/context";
import { trpcRouter } from "@@/server/trpc/routers";
import { userRouter } from "@@/server/trpc/routers/user";
import { applyWSSHandler } from "@trpc/server/adapters/ws";
import { WebSocketServer } from "ws";
export default defineEventHandler((event) => {
if (global.websocketServer) return;
const server =
event.node.res.socket && "server" in event.node.res.socket ? (event.node.res.socket.server as Server) : null;
if (!server) return;
const wss = new WebSocketServer({ server });
const handler = applyWSSHandler({
createContext,
keepAlive: { enabled: true },
router: trpcRouter,
wss,
});
const createCaller = createCallerFactory(userRouter);
wss.on(
"connection",
getSynchronizedFunction(async (ws, req) => {
const context = createContext({ req, res: ws } as CreateWSSContextFnOptions);
const caller = createCaller(context);
await caller.connect();
console.log(`Connection opened, client size: ${wss.clients.size}`);
ws.once(
"close",
getSynchronizedFunction(async () => {
await caller.disconnect();
console.log(`Connection closed, client size: ${wss.clients.size}`);
}),
);
}),
);
process.on("SIGTERM", () => {
handler.broadcastReconnectNotification();
wss.close();
});
console.log("WebSocket Server is listening");
global.websocketServer = wss;
});