-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Native support for web sockets #1491
Comments
@AndreasHald Have you ever heard of Mercure? |
Can't say i had. The idea looks interesting, but afaik sveltekit doesn't yet support SSE yet either. We are pretty invested in Apollo Graphql server / client, and i don't think they have a transport layer for mercury, but correct me if i'm wrong. |
Hi! Mercure creator here.
Basically, as long as you delegate to a Mercure hub (a server implementing the protocol), you don't have to deal with SSE directly. The app just have to do a Supporting this part of the protocol perfectly fits with serverless environments because you can delegate the long running connection (that is by nature incompatible with serverless) to a dedicated component, even if the serverless service itself is not compatible with SSE, Websockets and the like.
I don't know Apollo very well. I know that API Platform has native support for GraphQL subscriptions through Mercure, and AFAIU there is no need for client-side code. Using the native Anyway, I would love to see support for the protocol land in SvelteKit. Let me know if I can help in any way to make this happen (I can try to create a transport for Apollo for instance). |
I had the same requirement and initially got some dirty workarounds to make it work with just SvelteKit but it's not maintainable. I have come to understand the direction SvelteKit is being steered towards(i.e. serverless rendering) that makes it quite tough to be fully compatible with the traditional NodeJS SSR + Vite itself would still lead us to a lot of bundling issues for server-side libraries. After playing with SvelteKit for a few weeks, I decided to build a set of toolkit on top of SvelteKit and bring out the best possible monolith DX. For more details, please find my comment here. Though I haven't added:
but yes, the above are all planned! I'm just excited to see this post here as I was wondering the same why we can't support |
@cayter sounds interesting, i think we will migrate to use SSE when 1568 is resolved, as i understand there is a PR ready. How would you go about implementing export const graphql. Svelte kit supports the graphql standard very well out og the box. Because graphql specifies a single endpont just use a single file /graphql/index.js that supports the spec We use apollo server without any issues.
|
I probably need to give it a try again, I bumped into issues where Vite was bundling some of the server-side dependencies in the client bundle and broke the page rendering. But yeah I was thinking of supporting graphql (with websocket subscription) easily via |
I think we will be exposing a way to add middleware in |
So is there some guideline regarding how to integrate sockets with a svelte-kit app? As far as I understand, the path of least resistance at the moment is to use import { assetsMiddleware, prerenderedMiddleware, kitMiddleware } from './build/middlewares.js';
import polka from 'polka';
import Socket from 'socket.io';
const { PORT=3000 } = process.env;
const app = polka();
app.use(assetsMiddleware, prerenderedMiddleware, kitMiddleware);
const { server } = polka().listen(PORT, () => console.log(`> Running on localhost:${PORT}`))
const io = Socket(server);
io.on('connection', socket => {
console.log('connection')
}) I didn't try this yet, but it seems to be the recommended path. It bothers me somewhat because it isn't integrated in the build system (won't have access to the same environment variables and But assuming I go with that, but I am not sure how access to all the session information that I have in my svelte-kit app. I am also not very clear on changing the state of the socket server based on url calls. Should I send two requests from each URL in my svelte-app (one normal http call and one to the websocket server?) Should I add a middleware to |
@Xananax, well I did. And actually it is easy to integrate with the build process. You can specify your custom server as An example:
|
This comment has been minimized.
This comment has been minimized.
This comment was marked as off-topic.
This comment was marked as off-topic.
WorkaroundInject socket.io (or another websockets implementation) into the vite DEV server via the vite config: import { Server } from "socket.io";
export default {
plugins: [
sveltekit(),
{
name: "multiplayer",
configureServer(server) {
const io = new Server(server.httpServer));
// do websocket stuff
},
},
]
} https://github.com/bfanger/multiplayer-dice-game/blob/main/vite.config.ts For PROD use the node-adapter to generate the middleware and which you'll include in a custom server: |
Using adapter-node as middleware along with a websocket server outside of sveltekit means that, if for example you are using TypeScript and .ts database models (i.e.: my current structure is lib/db/models/[...].ts, fetched from endpoints), you'll need a lot of extra steps to make these usable. In my case this makes it not worth it to even support real time updates :/ |
This comment was marked as off-topic.
This comment was marked as off-topic.
This should now be addressed since #2931. Previously, |
@benmccann It would be great if we could get a quick description (or link to it) how we can use WebSocket with SvelteKit. Specifically for those web developers not so much involved with the inner workings of SvelteKit and Vite. |
This comment was marked as off-topic.
This comment was marked as off-topic.
As of now, Cloudflare Workers, Deno Deploy and AWS are supporting WebSockets |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
Can someone point me to a working solution to implement only the client into SvelteKit? Background: DIRECTUS now also has websocket support and currently i am polling the database. Having a subscription would be awesome here, but i seem to be unable to get the client implementation to work. |
I guess this https://joyofcode.xyz/using-websockets-with-sveltekit is actually the best what you can find. |
I've made a few different repositories with svelte-kit and some web socket logic. Please ignore my bad ts-ignores. |
Just install socket io and import that in the client side script tags |
No, that doesn't work. socket.io only supports socket.io |
even throught thats the best option for now, its not made with typescript and that adds a whole new level of complexity |
I agree I wish there was a more type safe way I thought of to do this, maybe in future I can, but at least for now there is a workable way. I could probably get it to be more type safe, but would require additional work. |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
I understand there's a lot of interest in this, but please don't comment expressing interest. Instead use the thumbs up on the issue. Commenting with expressions of interest makes it harder to find the comments discussing how to implement this and we do need to be able to easily find those details to come up with a design for this. I've hidden all comments that are not relevant to the implementation of the feature. The core team won't be implementing this in the near future as we're currently focused on a very exciting set of changes in Svelte 5 as detailed in our roadmap: https://svelte.dev/roadmap. However, we will periodically switch back to adding major new features to SvelteKit in the future. You can read more about our process here: https://github.com/sveltejs/svelte/blob/master/CONTRIBUTING.md#our-process. In team meantime, we do still welcome folks chiming in with technical details that may help this get implemented. Examples that we can follow would be very helpful. Also helping to compile which platforms/adapters can and cannot support the feature. It looks like Node, Cloudflare, Deno, and AWS support web sockets (#1491 (comment)) while Vercel and Netlify do not. We're continuing to review PRs from the community if anyone would like to take a stab at this! |
This seems like a very well-done implementation that provides control of the WebSocket server to SvelteKit's server logic: Surprised nobody has linked to this , yet. |
Bun has a socket server built in. Thoughts on whether or not it could be a viable alternative to node.js and solve our socket issue? |
Bun implements uWebsockets natively so, using it's NodeJS package should get you very close to it in NodeJS land. Besides, I believe the problem SvelteKit has is more about how to standardise this feature for any potential adapter and not so much about finding a backend that supports websockets. That said, I guess Bun adds for another backend with full support so the scale can start leaning towards those solutions. |
Also they suggest sveltekit-adapter-bun, which has websocket support built-in via their Exposed Websocket Server. Edit: |
This comment was marked as off-topic.
This comment was marked as off-topic.
We just merged #11649, which adds a |
then we can add socket.io server to sveltekit like how we do with express js ? |
This comment was marked as duplicate.
This comment was marked as duplicate.
About using websocket with adapter-node, I have an example to share here and it works well. I wrote a vite plugin with monkey patches to hack the As for adapter-cloudflare you can refer to this. In fact, the need for websockets represents the user's desire to handle raw requests before entering sveltekit. It is true that incorrect handling can break sveltekit, but the user will be responsible for this. I hope Sveltekit can provide a hook like It could look like below, and it will be handled before the request is processed by sveltekit . import {onServerMount} from 'svelteKit';
import {WebSocketServer} from 'ws';
onServerMount((httpServerInstance, preRequestHandle) => {
// for adapter-node
const ws = new WebSocketServer(httpServerInstance)
ws.on('connection',(ws)=>{
})
// such as cloudflare
preRequestHandle((req, res, next) => {
const upgradeHeader = request.headers.get('Upgrade');
if (!upgradeHeader || upgradeHeader !== 'websocket')return next()
const webSocketPair = new WebSocketPair();
const client = webSocketPair[0],
server = webSocketPair[1];
server.accept()
server.on('connection',(ws)=>{
})
res.status(101).set('webSocket',client)
})
}) |
Hi I just wanted to chime in Websockets where specifically designed to piggy back on existing http request response functionality. There are 2 questions if we want to implement this:
Firstly: Note that the parameter in So how can we implement websockets keeping the feel of api routes? I see 2 possibilities:
// called AFTER kit has upgraded the GET request to websocket protocol and ws "open" event is issued
export function UPGRADE(
event: RequestEvent, // original event for the ws upgrade
ws: WebSocket //
) {
ws.onmessage = e => {...}
ws.onerror = e => {...}
ws.onclose = e => {...}
// WebSocket has `reqId` property
// ws is stored in a global object so if you want to send something you need to fetch the websocket from a global map
} |
For me it would make sense to have it a little more explicit. I am thinking of something like // /src/routes/.../+server.ts
export const websocket: WebSocketHandler = async ({wss}: {wss:WebSocketServer}) => {
wss.on("connection", (socket) => {
socket.on("open", ()=>{/*...*/});
socket.on("message", ()=>{/*...*/});
socket.on("close", ()=>{/*...*/});
socket.on("error", ()=>{/*...*/});
// It would also allow for server initiated conversation
socket.emit(/*...*/);
}
// Broadcasting to all clients would be possible
wss.broadcast(/*...*/);
}; OR the bun way: export const handleWebsocket = {
message: (ws, msg) => {
ws.send(msg);
},
//optionally, doesnt have to be set - can be used to deny websocket
upgrade: (req, upgrade) => {
upgrade(req, {data:1});
}
} Edit: now I have second thoughts on whether this is the best form for it, but it feels natural. The downside I see would be that this exported websocket function would be called only once (on server startup) and then all the action would happen inside the callback (wss.on) |
any implementation should take this in mind |
Assuming that the request that would trigger the We also want to ensure solutions for handling sets of connections, or accessing a specific connection is well supported. // Broadcast message to a specific user's clients
function broadcastMessage(userID: string, message: any) {
if (clients[userID]) {
clients[userID].forEach((socketID) => {
io.to(socketID).emit("message", message);
});
}
} This is still the biggest/only thing missing for me using SK day to day. |
This comment was marked as duplicate.
This comment was marked as duplicate.
After looking into this more deeply - could we consider both WebSocket and WebTransport support? WebTransport (built on HTTP/3) offers some compelling benefits like improved connection handling through QUIC and better multiplexing. While it's not yet supported in Safari, a WebSocket fallback pattern would provide complete browser coverage while letting us take advantage of WebTransport's improvements where available. Since Deno 2 has strong HTTP/3 capabilities, it would be interesting to explore how SvelteKit could leverage both technologies to give developers options for real-time communication needs. Having both would be the absolute bleeding edge and best opportunity for developers and UIs. |
This comment was marked as duplicate.
This comment was marked as duplicate.
I just went through the implementations offered by various vendors. Deno, Bun, Node, and Nitro appear to use a WebSocket API which matches the browser spec (example of using it). Whenever we can use APIs adhering to the spec that is best Cloudflare seem to have their own API. It's slightly different from the spec. E.g. it uses Meanwhile, AWS Lambda appears to go completely off script with an API totally different from anything else and has I found https://crossws.unjs.io/, which tries to introduce an API that works across various implementations |
We've been attempting to migrate our app from sapper to sveltekit and ran into the problem of web sockets, in sapper we could simply attach the WebSocket server directly to the express server and be done with it, but as per Rich Harris' comments here and here here in sveltekit we don't want to expose direct access to the middlwares thus promoting the node adapter over the serverless ones.
However seeing as some of the serverless providers are starting to support web sockets (cloudflare) (begin) (AWS Lambda) should sveltekit provide a way to handle these connections directly?
A native approach to this could also potentially provide a tool to solve this issue and this
Describe the solution you'd like
An interesting solution could be to expose functions in endpoints in the same way we handle http requests, and then let the adapters handle the rest
routes/api/index.ts
A concern with this approach could be mixing protocols, within an endpoint could be confusing. Another could be if this becomes too complicated since as far as I know the initial handshake to start a WebSocket connection is handled over http, would this then be handled directly by sveltekit which could be considered too much "magic" since it would have to intercept a get request that would then not make it to the get handler in the endpoint. Or should we let the user implement the get endpoint and return the WebSocket pair and upgrade header.
Describe alternatives you've considered
The way we go about it today is a small script that manipulates the build output of sveltekit as such however this does not work in dev mode which is a pain point.
Is this a feature that you feel would suit sveltekit? are there any considerations I've overlooked?
The text was updated successfully, but these errors were encountered: