💬 Realtime Chat and Gaming Apps and Serverless WebSockets #
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 #
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.
Real‑time #
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: Serverless WebSockets #
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.
🧱 What we’re Building #
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 🙄.
🍶 Server Side Ably Setup #
Ably have a JavaScript SDK which will work just-fine with Svelte. Start by adding this ably
package to your project:
SvelteKit Ably Server Code #
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 ably
.
The 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.
SvelteKit Ably: Load Function #
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.
🧑🏽 Client‑Side Ably Setup #
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 Svelte
Action!
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 have a DOM
element which the chart is drawn to. Typically, you use JavaScript code to perform that 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.
-
In line
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
onMount
in lines17
–22
, using the token generated server side.
Connection Upgrade to WebSocket #
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
in lines 28
– 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:
❤️ A Little about the Game’s Design and Svelte Implementation #
The game just relies on JavaScript and HTML elements. Each grid line is an HTML button. I used CSS to get them in the right place and turn them the right colour. There are Svelte components to represent horizontal and vertical lines, and grid rows which all combine into a grid component. Buttons have descriptive text, for accessibility.
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.
🛠️ SvelteKit Ably: Extensions #
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 .
🗳 Poll #
🙌🏽 SvelteKit Ably: Wrapping Up #
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.
🏁 SvelteKit Ably: Summary #
How can you add real-time chat to your SvelteKit app? #
- 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.
Why use Serverless WebSockets? #
- WebSockets are now a standard JavaScript Web API and there are Node packages like ws or C++ and Rust implementations such as uWebSockets and tungstenite. These are great if you have the infrastructure already or have time. If you want quickly to build out a proof-of-concept or, even, if you anticipate unpredictable load, then serverless is well worth a look. Ably, together with alternatives like partykit can help you get going quickly, if you do pick the serverless route.
How can you use Ably in a SvelteKit app? #
- Fortunately, the Ably JavaScript package works just fine with SvelteKit. You will want to create an Ably client token server-side in a `+page.server.ts` route and pass it to the client. The Ably JavaScript SDK will create the tokens for you. The client will then use the token to establish an HTTP connection to Ably which then is upgraded to a WebSocket. Again, we saw this is something the Ably JavaScript package can handle for you. It has full TypeScript support. To get going, just install it with `pnpm add ably`.
🙏🏽 SvelteKit Ably: Feedback #
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!
https://t.co/LZ6lcj2z2U
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.