Native support for web sockets
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
// Handle post requests
export const post: RequestHandler = async (request) => {....}
// Handle web socket requests
export const ws: WebSocketRequestHandler = async (request) => {....}
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.
const instance = createServer({ render: app.render }).listen(PORT, HOST, (err) => {
if (err) {
console.log('error', err);
} else {
console.log(`Listening on port ${PORT}`);
}
});
app.server.installSubscriptionHandlers(instance);
export { instance };
Is this a feature that you feel would suit sveltekit? are there any considerations I've overlooked?
@AndreasHald Have you ever heard of Mercure?
@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.
sveltekit doesn't yet support SSE yet either
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 POST request to the hub to broadcast an update to all connected clients.
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.
We are pretty invested in Apollo Graphql server / client, and i don't think they have a transport layer for mercury
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 EventSource JS class looks enough. But maybe that a better integration with Apollo could be created?
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:
export const wsto support websocketexport const graphqlto support GraphQLexport const grpcto support GRPC (haven't dive deep into this yet but will be very much needed for successful startups who wants to slowly move some monolith pieces out to another service)
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 export const ws and export const graphql! Good job.
@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 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:
export const wsto support websocket
export const graphqlto support GraphQL
export const grpcto support GRPC (haven't dive deep into this yet but will be very much needed for successful startups who wants to slowly move some monolith pieces out to another service)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
export const wsandexport const graphql! Good job.
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 export const graphql though I haven't really come to this step yet, will share more once I'm onto it and will very likely be adopting:
- https://github.com/websockets/ws
- https://github.com/enisdenjo/graphql-ws
I think we will be exposing a way to add middleware in adapter-node (https://github.com/sveltejs/kit/pull/2051), but if anyone wants to take a stab at adding more generic support that also support the serverless platforms, that still sounds valuable
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 adapter-node, and add a file that uses the built svelte site:
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 import.meta goodies, won't be using typescript unless I set up a separate build, ...).
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 adapter-node?
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
@Xananax, well I did. And actually it is easy to integrate with the build process. You can specify your custom server as entryPoint in your svelte.config.js file. Your can read about that here: https://github.com/sveltejs/kit/tree/master/packages/adapter-node#entryPoint
An example:
- Put your custom server at your [YOUR_PROJECT_DIR]/server/index.js right next to [YOUR_PROJECT_DIR]/src
- Do not forget to add polka to your dev dependencies and to run
npm installagain - Add
entryPoint: 'entryPoint: 'server/index.js','in your adapter option within the kit.adapter section of yoursvelte.config.js - run
npm buildand see the magic happen.
I don't think that we'd want to provide built-in endpoints in that manner. I would really like to provide the feedback to your teacher that this assignment is not fair to open source maintainers. I welcome people getting involved in open source, but would encourage them to do so because of their own experience with the project. I've had this happen numerous times where people need to check a box because of a school assignment and it almost never results in code that we can accept to the project and instead just places more burden on us. This isn't your fault at all and I'm happy you're interested in Svelte so I hate to write something discouraging. But I do wish this trend of making us do more work for other people's school assignments would die. Your teacher should be responsible for reviewing all code changes and not making us do it. I am simply not interested in being a TA and will reject any contributions to the project without review if they are for a school assignment because it is not a scalable use of our time to do teaching and review of school assignments. That's a teacher's job and they should stop trying to foist their job upon others who didn't volunteer for such duties
Any news on Websockets, is there an ETA when Websocket will be easily available within SvelteKit for DEV and PROD?
Looking at the Endpoints docs with its await db.get(slug) I think SvelteKit is clearly seen as backend, so supporting Websockets seems just the next logical step.
Workaround
Inject 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: https://github.com/bfanger/multiplayer-dice-game/blob/main/server.js
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 :/
@Rich-Harris any guidance on the priority to support websockets in ‘22? We have a realtime api based on Elixir and Phoenix, and the story around websockets is the only aspect giving us pause with adopting sveltekit.
It bothers me somewhat because it isn't integrated in the build system (won't have access to the same environment variables and import.meta goodies, won't be using typescript unless I set up a separate build, ...).
This should now be addressed since https://github.com/sveltejs/kit/pull/2931. Previously, adapter-node had a second bundling step using esbuild. Now Vite does everything
@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.
+1 for WebSockets. I love SvelteKit and wanted to build a real-time game on it, but lack of support requires me to separate my back end and front end at this point.
As of now, Cloudflare Workers, Deno Deploy and AWS are supporting WebSockets There is gonna be more and more WebSocket support on serverless platforms, having some native and first-class WebSocket support is something we truly need to make immersive experiences that can go realtime
Any updates on this?
This really is the last piece that's missing in SK to finally replace all my other stacks. Hope it will be there soon :-)
Just FYI, for those who are not running on serverless technology, you can rely on this to setup your own HTTP server alongside the websocket server. I had successfully setup a Fastify server + tRPC with subscriptions.
I am running my own setup (not serverless) I would finally decided to run a node instance as my web-socket server. It is all well and good, but it would be really nice to have this built-in, as it would greatly reduce the maintenance and code complexity. This is currently my ONLY sveltekit ask!!!
Cloud Run supports Websockets as well, which is a serverless technology... this could change the game in frameworks. I predict this will be a thing one day, just hopefully sveltekit before nextjs. This is so important for modern app development and would make sveltekit the most powerful framework.
J
As scary as it sounds, I think that this may be a make or break feature for SvelteKit VS Nextjs
It seems solid-start included the initial implementation for websocket, probably SvelteKit can borrow some ideas from it too.
Disclaimer: I'm not sure if it only plays well with node adapter or the serverless platform like netlify/cloudflare worker as well.
Hopefully we'll have native websockets very soon but anyone looking for a solution in the meantime should check out JoyOfCode's video or article on a workaround.
When will SvelteKit have support for WebSocket?
Are there any news about the websocket support? I need it for my project and when i tried to separate the client and the server it became very messy.
~~Just keep in mind that "native support" is impossible (afaik) for any serverless deployment, such as vercel.~~
~~This is because this type of deployment does not have a permanently running server that could send WS data to it's clients or keep the connection up in the first place. Using the svelte node adapter means opting-out of serverless deployment.~~
Thanks for the correction @jdgamble555. Still, it's important to point out, that the hoster might not support WS, which could still be a dealbreaker in many cases, which is an important piece of information to know about for a dev starting a project.
If this is the case where you are planning to host your project (for me that would be Vercel), maybe you want to create a separate server for WS. For my project, I opted for a mono-repo architecture like this. so I can keep all the serverless benefits:
/app # the sveltekit app, w/ adapter-auto
/server # a simple express server, w/ socket.io
/shared # shared code. I use it for TypeScript types and shared utility methods, etc. With some tsconfig tinkering you can get your project so you can import your shared code like so: `import xy from '$shared/myCode'`, for both the svelte and the server
Then I simply deploy my svelte app to Vercel and my node express server w/ socket.io to some conventional host.
Just keep in mind that "native support" is impossible (afaik) for any serverless deployment, such as vercel.
It is definitely NOT impossible for serverless technologies to support a version of web sockets:
- Cloud Run
- Cloudflare - (which is what Vercel uses under-the-hood for edge functions)
Even if you were right, which is not entirely the whole picture, Vercel could theoretically create a different deployment option like the /api folder, say /socket, which would deploy differently than the rest of the app. It is already doing this with edge functions, static files, and regular aws lambdas.
The thing is, this would need to start with Vercel -- given that Vercel supports SvelteKit -- then trickle down to SvelteKit -- and other adapters and services would be modified later to support it.
J