-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Native support for Websockets #12961
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
Conversation
|
…gestions, adjusted handling
preview: https://svelte-dev-git-preview-kit-12961-svelte.vercel.app/ this is an automated message |
@@ -54,9 +54,10 @@ const allowed_page_methods = new Set(['GET', 'HEAD', 'OPTIONS']); | |||
* @param {import('types').SSROptions} options | |||
* @param {import('@sveltejs/kit').SSRManifest} manifest | |||
* @param {import('types').SSRState} state | |||
* @returns {Promise<Response>} | |||
* @param {{request: import('http').IncomingMessage, socket: import('stream').Duplex , head: Buffer}?} upgradeRequest | |||
* @returns {Promise<void | Response>} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not that familiar with UPGRADE
, but is it true that it sends no response? A quick peek at MDN makes it appear to me that it does send a response
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade#overview
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The response appears to be sent back through the socket itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There does appear to be some variance in the way the response is sent though, for example Bun does not send a response, but Deno does appear to return a standard HTTP response.
Socket.IO also returns a response but they refuse to just give you the resp object, and instead insist on binding directly to a Server so they can send it themselves.
If we look at the Node.JS server upgrade event, they specify the data is sent back through the socket, and their on upgrade handler does not even support sending a standard response object
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would love maintainer/community input here, its definitely a fun issue to try and solve for everyone :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like Socket.IO may actually support the same interface
https://github.com/socketio/socket.io/blob/91e1c8b3584054db6072046404a24e79a17c1367/packages/engine.io/README.md?plain=1#L40-L58
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't had any luck getting this to work locally
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry, I hadn't event noticed on first glance that UPGRADE is not an http verb like the others and it's an http header. I'm afraid I'm not terribly familiar with web sockets. I think we'll need to find another way of expressing this that doesn't mirror the API we use for HTTP verbs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Understood!
One thing that's worth mentioning is that this approach allows for different websocket handlers to be created on different routes, and for all other aspects of the requests and routing to use the existing SK response handling.
The incoming request is different, as the servers don't appear to pass these get requests through to middleware, so the existing middleware handling had to be somewhat copied to the server.on("upgrade")
handler.
Thank you, I'm excited for this functionality. I'm not quite sure this is the right API though. As @benmccann mentioned elsewhere, treating I don't think it's just a naming issue though — I think this API is probably too low-level if I have to interact with |
Hey @Rich-Harris, We are also discussing in the Svelte Discord here. What do you think about exposing the |
Here is an example of the above discussed solution. This solution has some very specific differences which should be considered:
That being said I don't think either of those things are bad, and I think that if we make the names of some variables or exports here a little more appealing (and get my bad types in order) this has the potential of being a very good solution. |
I take it back you can do different paths using this feature of crossws |
What about exposing exposing an action-like object in Something like: import type { Socket } from './$types';
export const socket = {
open: (peer) => {
peer.send({ user: "server,", message: `Welcome ${peer}!` });
peer.publish("chat", { user: "server", message: `${peer} joined!` });
peer.subscribe("chat");
},
message: (peer, message) => {
if (message.text().includes("ping")) {
peer.send({ user: "server", message: "pong" });
} else {
const msg = {
user: peer.toString(),
message: message.toString(),
};
peer.send(msg); // echo
peer.publish("chat", msg);
}
},
close: (peer) => {
peer.publish("chat", { user: "server", message: `${peer} left!` });
},
} satisfies Socket; This way WebSockets can be created on a per-route basis and each step (open, close and message) could be properly handled by each platform with all of its shenanigans (👀 looking at you AWS lamba) Or even better, maybe this object could be passed directly to crossws |
Seems like implementing things this way instead would still be pretty straightforward, we would just need to change the root usage to be the shape crossws uses for routing, and do some work in the middle to actually load the correct paths websocket handlers. |
Yeah, I think that's a nice idea. Looks like Nitro imports a per-adapter implementation of crossws, which is something we could do too. E.g.: I also noticed that Nitro marked their feature as experimental: https://nitro.build/guide/websocket#opt-in-to-the-experimental-feature, which is something we could consider as well if we want a bit of flexibility in changing the API. |
Yes the current approach I am working on with crossws would I believe have the adapter import occurring at the SK adapter level. Allowing for the same approach. |
Closing in favor of new PR #12973 |
This PR is intended to add a path forward to natively support Websockets and similar protocols directly in SvelteKit by implementing an
UPGRADE
handler to be used similarly to existingGET
,POST
,HEAD
+server.js
exportsThis PR will need to evolve to reflect the ideal implementation, and to correct things I have not yet like types, supports, etc...
Resolves
Resolves #12358Resolves #1491
Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
Tests
pnpm test
and lint the project withpnpm lint
andpnpm check
Changesets
pnpm changeset
and following the prompts. Changesets that add features should beminor
and those that fix bugs should bepatch
. Please prefix changeset messages withfeat:
,fix:
, orchore:
.Edits