In this SvelteKit Ably post, we talk about adding real-time events to your SvelteKit app. I have been trying out various event-driven architecture solutions recently, and have been fascinated by the offerings. WebHooks and REST hooks are the protocols I am most familiar within this space. Though, Pub-Sub and WebSockets are probably a little more common.
WebSockets enable two-way, stateful connections. HTTP connections usually involve a client requesting a document and the server responding with it, in a request-response pattern. For a real-time chat or game, clients will need to send messages or moves, live, up to the server. Similarly, the server will need to push these received updates to other participant clients; that is, without the client individually requesting them. The clients could ping repeatedly, to check for updates, over HTTP, though an open WebSocket can offer enhanced efficiency.
If you use front end tooling with Live Reload or Hot Reloading, you might already be running a WebSockets service! Here the browser opens up a WebSocket to the dev server, and typically, when an input file is changed the server closes that connection, which the client interprets as a signal to refresh the page.
We know why WebSockets are relevant for real-time chat and gaming, but what exactly is real-time? Typically, when we talk about real-time here, we need latency (the time taken for data to pass between client and server) to be below 100 milliseconds. For fast-paced, action games players will be targeting something below 20 ms, though for chat and our little strategy game, something slower would be tolerable.
Ably’s platform offers real-time serverless WebSockets; ideal for adding real-time chat or multiplayer gaming to your SvelteKit app. Although you can run a SvelteKit app in node on a traditional server, the serverless pattern is currently quite common, and well-suited to SvelteKit. Alternatives to Ably which you might be familiar with are partykit, PubNub and Pusher. Personally, I have only tried Ably so far; drop a comment below if you have tried others.
We look at a simple SvelteKit strategy game in this post. I used to play the game on long car journeys, albeit with two different coloured pens and a scrap of paper! We use Ably, and the basic setup will not look too different whether you have a more sophisticated game or real-time chat in mind.
I created the Squavably game as a way to try out Ably’s serverless WebSocket offering. It is based on the Squares classic game. There is a tradition in the Svelte community to bolt “Sv” onto the start of any app name. Look no further than Svoast , SvHighlight and Sveriodic Table for examples. There was no option but to call the game Sqvuably 😅.
We won’t build the game from start to finish in this post instead, we’ll focus on the highlights, or should I say SvHighlights 🙄.
ably package to your project:
I based my project on an Ably Labs project, which uses older SvelteKit APIs .
I kept this logic on a
+page.server rather than
+page.ts, since we want to avoid sharing the API key with clients. On top, there is a little server-side
state for the game, allocating players to games sessions.
Notice, the ably package has full TypeScript support, and we import
Types as a named import from
actions block contains logic for logging the user in. If you
are new to SvelteKit forms, take a look at the recent SvelteKit Forms post where we explore the APIs building a grammar checking app. Here, we use the front end form to get the player name and associate this information with a
new SvelteKit session. These data are provided before the WebSocket is initialized, and we store
the session data in an HTTP-only cookie. Then, we redirect the user browser to the “
/” route on successful form submission. This will involve the page load function, now with
access to the new user-associated session data.
The load function is most useful once the user has filled-out the form, and we have a SvelteKit
session. We initialized
ably right at the top of the file:
Now, in the load function, we create a new Ably auth token for the user:
This is all server-side, so far. WebSocket connections start their life as regular HTTP
connections, which are then upgraded. Following a regular HTTP request-response pattern, we will
initialize this HTTP connection from the browser. So, the most important part here, is passing the
token to the browser, allowing it to kick off the Ably connection. Returning
token from the load function makes it available as a prop client-side.
I extracted a lot of the game-related detail here, and there is a link, further down, for the full code.
Often, I prefer to use Svelte Actions for component related setup. Here, though, an
onMount approach seemed more natural. Keen to see if you have a clean way of doing this setup in a
onMount code runs after the page has been rendered. You might
reach for it if you are setting up a chart for example. You will
drawing task. You cannot draw to the DOM element before it exists, though! Placing the drawing
code in an
onMount function is a way to make sure you avoid this,
as the function is only called once the DOM is rendered.
9, we have access to the Ably token which we exported from the server load function.
We create a variable for an Ably channel in line
13. Channels isolate the apps messages from other apps we have. Alternatively, for a multi-player real-time game, you might have separate lobby and in-game chats. Each here could have its own channel.
We create the WebSocket within
22, using the token generated server side.
Once we start the connection process, we just wait for the connection to complete. Under the hood, the HTTP connection will be upgrading to a WebSocket. Pull open your browser developer tools and track network requests. You should see a regular HTTP 200 GET request and then a 101 Switching Protocols GET request, where Ably upgrades the connection for you!
As a final step, the client needs to subscribe to the channel. Notice, we have a callback function
32. This callback details what we want to happen when we receive a new message on the WebSocket.
For a chat app, you would want to render the message for the user to read it. For the Sqvuably
game, the message will be an update with the opponent’s move.
The messages can have arbitrary shape to suit your application. Here is a sample message from Sqvuably:
And an example for sending a message into the Ably channel:
Given the structure, you might end up using a lot of prop drilling. To minimize that, I used Svelte stores for maintaining state on which player’s turn it is and whether a grid line has been claimed yet, and if so, by whom. Then, components can pick off the state they need from, avoiding prop drilling.
Typically, in a game, before all lines are covered, there is a point where it does not make sense to continue playing; that would be because neither player could claim any new squares. The Svelte stores help to simplify the logic for working out when this state has been reached.
I only really scratched the surface on what Ably itself can do, and also how you can integrate it with event-driven architecture. I have a few ideas for extensions, and am happy for you to reach out with yours: in a comment below, or however else you prefer.
The most obvious missing piece is renewing Ably tokens. These games should be quite short, so it was not an early priority, though I will look into setting it up, so I can extract the logic to other more sophisticated applications I work on.
- Ably Presence: Presence offers an alternative method of communication on the channel. Using presence, you can, for example, automatically send “Vonda has just entered the room” style status updates in chats.
- Upstash Redis: this is a handy service which offers serverless Redis . Redis would be fantastic for storing a leader board, which could shine a light on the most prolific players. Disclaimer: I have done writing work for Upstash in the past.
- Kafka: Apache Kafka is an event store for real-time events. We might use it to store privacy-friendly player stats like average time to win. These data could be analysed periodically to update leader boards and other stats cached in Upstash Redis. Upstash offer serverless Kafka and Confluent is another alternative .
In this post, we took a big-picture look at how you might set up a real-time SvelteKit Ably app. In particular, we saw:
- what WebSockets are, and why you should consider using them
- how Ably serverless real-time can save you time building a real-time app
- how to set up Ably in your SvelteKit app
Please see the full repo code on the Rodney Lab GitHub repo . I do hope you have found this post useful and can use the code as a starting point for your own real-time app. I have been looking at event-driven architecture recently, using tools like ClickHouse for analytics, as well as trying out Ably. Do you want to see more content on what I am learning around these topics? Are there services or tools you are curious about and would like to see some content on? Drop a comment below or reach out on other channels.
- WebSockets are a good technology to consider for real-time chat apps. They are a little different to HTTP connections, which use a request-response pattern. On an established WebSocket, both clients and servers can push messages at any time. This can offer a more efficient solution than polling, for example on an HTTP connection. Ably offer real-time WebSockets and will help you hit the ground running if you have tight time constraints.
If you have found this post useful, see links below for further related content on this site. I do hope you learned one new thing from the video. Let me know if there are any ways I can improve on it. I hope you will use the code or starter in your own projects. Be sure to share your work on Twitter, giving me a mention, so I can see what you did. Finally, be sure to let me know ideas for other short videos you would like to see. Read on to find ways to get in touch, further below. If you have found this post useful, even though you can only afford even a tiny contribution, please consider supporting me through Buy me a Coffee.
Just dropped a post taking you through how to set up serverless WebSockets with Ably in SvelteKit.— Rodney (@askRodney) May 3, 2023
Handy for real-time games and also, chat.
Also, see what WebSockets are, and why they are a good match for real-time apps.
Hope you find it useful!
Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on Twitter and also askRodney on Telegram . Also, see further ways to get in touch with Rodney Lab. I post regularly on SvelteKit as well as Search Engine Optimization among other topics. Also, subscribe to the newsletter to keep up-to-date with our latest projects.