Rant on SvelteKit: I Didn't Even Know He Had a Server

· 597 words · 3 minute read

I’m a backend engineer. With that out of the way, Svelte have spoken to me in ways no other Javascript framework has done. It’s a pleasure to build with it. Reactivity comes easy.

I have my list of S-tier software, I’m sure we all do. PostgreSQL. Linux. Nginx. ProseMirror. Git. Things you reach for that are impeccably well-designed. Written by people who’ve stared at the problem for a long, long time producing strong, consistent models for the domain. It might not be the simplest tool to use, but you rather get stuck than brick your computer and in that way you can always ask/Google your way forward. SvelteKit was up there for me.

I never used any of the server features of SvelteKit though – it felt a pleasure to use as a client library. You know, send mostly prerendered, static HTML to the client and have them hydrate the data. It seems to pre-render most things well; turning off Javascript I can see it produces a nice snapshot of the HTML.

Until my dumbass realized that “not using server-features” pretty much don’t really exist, so whether you like it or not you are getting a server.

A server that runs your client code.

Oh no.

A server that shares state for all your requests.

Oh dear.

But at least the SvelteKit stores are client-side only, and the-

Dangerous Store behavior with SSR

Bummer.

If you write and read to a SvelteKit store in your code that executes on the server: you’ve got yourself a data leak.

Svelte uses +page.server.js for files that run on the server, so it shouldn’t be that easy to get it wrong on first glance. The other file type for loads are +page.js which, of course, runs correspondingly on the client. Unfortunately, +page.js runs on both the client and server, meaning that it is a lot easier to get it wrong.

The SvelteKit markup is contained in a +page.svelte file. The server-side renderer also reads the +page.svelte and is going to read the Svelte stores there too. If we’ve done a good job, they’re going to return the default value as they’re never written to. It seems to be that if we write to a store in +page.svelte we might also run into issues, as the SSR is executing that code too. In my Grug-brained opinion, it is pretty hard to reason about what code runs where and what causes issues.

With that: +page.server.js, +page.js and +page.svelte all execute code on the server. This kind of leads to… How do I keep client-only state in a safe way?

It’s almost inevitable for the server to read from Svelte stores is my understanding. However, if you write to them, you must pay the eternal sin. There’s a lot of people out there crossing their fingers that their code is correct. Bless them us.

Without a doubt, these decisions are all better than the other simple replacements we can come up with, it’d be naïve to think “duh, why don’t they just…”, but I do get the feeling that there is something missing here.

Looking at the documentation, almost all SvelteKit code examples use global stores, which is something that excaberates the problem. The documentation on State Management contains mostly “don’t do this” with writing to a global variable, but it seems more nuanced than this to me. Perhaps it really isn’t though.

Lesson to take with me until next time: sometimes you really should begin by RTFM, and in addition to the M, go search for best practices in other places.1.


  1. https://www.youtube.com/watch?v=K1Tya6ovVOI, https://www.youtube.com/watch?v=EyDV5XLfagg ↩︎