I am developing an application using Laravel, Inertia and Svelte. It's currently running SSR.
Here's a simple code snippet that I use to set up the <title>
tag in the <head>
section, using Svelte:
import { title, desc } from '@/utils/app';
...
<svelte:head>
<title>{$title}</title>
{#if $desc}
<meta name="description" content={$desc}>
<meta name="og:description" content={$desc}>
<meta name="twitter:description" content={$desc}>
{/if}
</svelte:head>
Both title
and desc
are writable stores. Now I am facing an extremely strange issue.
When I visit a page A, and then inspect the HTML source code to make sure that SSR is working perfectly, I get the title "Page A" in <title>
for page A. So far, so good.
Now if I visit a page B in another tab, I get the title "Page B". Surprisingly, refreshing page A's source in the previous tab also shows "Page B" in <title>
.
Why is this happening?
It seems as if though the Node.js process running in the background for SSR, launched by Laravel Inertia, is not getting destroyed after server-side rendering for a given request. It seems that the writable stores are retaining their old values. But still I'm not sure what exactly is happening here and why?
This has been warned against extensively, and there's even a video from Rich Harris that touches the subject. Apologies, I don't have the time to locate it.
Bottom line: If you're doing stuff like this:
import { writable } from 'svelte';
export default writable();
Then you're creating a singleton as per standard JavaScript module rules. In the browser, there is just one user, so singletons are no problem. However, in the server there are multiple users using the same NodeJS server, and the above store is still a singleton, but in the server that serves requests for multiple users.
Bottom line: Don't set stores in the server. If you have to, combine them with getContext
/setContext
. When attached to the hierarchy, they'll work. This is how Sveltekit-provided stores actually work.