Global Stores Are Dangerous

  Рет қаралды 12,983

Huntabyte

Huntabyte

5 ай бұрын

The idea of exported global state (stores or $state objects) from a module may be fine if you're running a SPA, but as soon as Server Side Rendering (SSR) is introduced by a meta-framework like SvelteKit, this is a major foot gun.
In this video, we'll discuss why a global module state is problematic when combined with SSR and how we can safely implement a global app state that isn't too burdensome to use!
🔗 GitHub Discussion: github.com/sveltejs/kit/discu...
📜 SvelteKit State Management Docs: kit.svelte.dev/docs/state-man...
🚀 Modern SaaS Course: hbyt.us/modern-saas
💬 Discord: hbyt.us/discord
🐦 X/Twitter: hbyt.us/twitter
🖥️ Setup Stuff: hbyt.us/gear
📃 Topics Covered:
- SvelteKit v2
- Sveltekit 2
- Svelte 5 global state
- Svelte 5 reactivity
- Svelte 5 stores
- Svelte 5 class state
- Svelte 5 global reactivity
- Svelte 5 tutorial
- Svelte stores SSR
- Svelte SSR security
- Svelte store security
- Svelte security tips
- Svelte 5 reactive classes
- Svelte 5 features
- Svelte Context API
- Svelte 5 Context

Пікірлер: 91
@Huntabyte
@Huntabyte 5 ай бұрын
Forgot to go through the official SvelteKit Docs page on this topic, so I'll link it here. Highly recommend reading through this! kit.svelte.dev/docs/state-management
@Nintron
@Nintron 5 ай бұрын
Time to nervously watch hoping I'm not making any of these mistakes.
@Huntabyte
@Huntabyte 5 ай бұрын
😂
@SoloElROY
@SoloElROY 22 күн бұрын
Aaaaand I do
@phantasmalmira5430
@phantasmalmira5430 5 ай бұрын
One tip for using context API is to create unique key using Symbol() rather than strings so that there will never be any conflicting keys
@omomer3506
@omomer3506 5 ай бұрын
This should totally be a playlist of its own, Sveltekit No Nos
@webstuffzak
@webstuffzak 5 ай бұрын
Can't wait for the video about the power of classes with runes. Very very interested. Love your content!
@coffeeintocode
@coffeeintocode 5 ай бұрын
Another good video & thanks for calling out that this isn’t a SvelteKit specific issue. All meta frameworks will suffer from this
@zzonawav
@zzonawav 5 ай бұрын
TypeScript Classes are crazy powerful used in this context.. I have been doing some things with JavaScript Canvas API with type instantiation and svelte components .. the performance and layering I am able to achieve with theses SSR components is blowing my mind.. it all works with reactive params! Really a game changer. I know a lot of people hate on typescript but the typescript class is my go to design pattern for many things in svelte.
@hanshurtig5943
@hanshurtig5943 3 ай бұрын
As far as I can tell, you could also use the page store to set state on the client side: // some js, ts or svelte file, but never .server.something import { page } from '$app/stores'; import { derived } from 'svelte/stores'' export const user = derived(page, $page => $page.data.user) Then import it wherever you want. Or am I missing something?
@AZombieHippie
@AZombieHippie 5 ай бұрын
Do you find that classes in Svelte 5 have some unique offering beyond returning an object from a function closure with getters? I've been really happy so far with closures for encapsulating business logic nicely
@CodeZakk
@CodeZakk 5 ай бұрын
Hi thanks nowadays everybody is talking about nextjs and react you and joy of code the only channel talking about sevelte and sveltkit thank you. I started watching your channel and learning svelte for a while now thanks for your content!!🎉🎉🎉
@seunghwanjeong5348
@seunghwanjeong5348 5 ай бұрын
Hi! Thank you for making amazing video every time :) I think misunderstood the concept of runes. I would try what you recommend👍🏻
@Huntabyte
@Huntabyte 5 ай бұрын
You're very welcome!
@xWe2s
@xWe2s 4 ай бұрын
Can you make a video about sveltekit v2 + svelte v5 including Runes? Are there something specifics in setting such thing up?
@acharafranklyn5167
@acharafranklyn5167 5 ай бұрын
Thanks for making these videos again.... you took a lot of break
@Huntabyte
@Huntabyte 5 ай бұрын
You're welcome! A break from videos but not a break from Svelte/code 😉 I've learned a ton during that break that I'm looking forward to sharing!
@gunarcom
@gunarcom 5 ай бұрын
Thoughts on the solutions using weakmaps on the server to prevent leakage?
@Huntabyte
@Huntabyte 5 ай бұрын
I haven't dug into those enough to form thoughts, I just went with the recommended approach from the SvelteKit docs!
@gunarcom
@gunarcom 5 ай бұрын
@@Huntabyte that's fair, I've been following that github discussion thread for months.. I am using one of the "ssr safe" packages on a personal site and it seems to work well, it uses weakmaps under the hood, which is similar to the way context stores work from what I gather. Looking forward to runes and hopefully addressing this pain point that I think most everyone runs into and great vid btw :D
@ntnon
@ntnon 4 ай бұрын
good good content
@AShaheen92
@AShaheen92 5 ай бұрын
Using Classes with state and setting it as a context is at another level! Can’t wait to start using svelte 5 after being stable. You really impress me with every video you upload. Wish you great time
@jaycool-lb9kj
@jaycool-lb9kj 5 ай бұрын
For sure! Cant wait to experiment with this
@Huntabyte
@Huntabyte 5 ай бұрын
Thanks a ton! I love the classes a little bit _too_ much, excited to share more about them!
@jesper.ordrup
@jesper.ordrup 5 ай бұрын
Really great to bring this up again. While its not s svelte issue per day it sure becomes a svelte related problem when svelte adds functionality that relies on this. I wish that svelte stores directly solved this, also compile time warnings rather than workarounds. It makes svelte less "simple"
@Huntabyte
@Huntabyte 5 ай бұрын
The problem is really only introduced with SSR, so if you're using Svelte as an SPA with 0 server side rendering, then that global variable would be global only to the client, in that case its fine. The same would be true in Nuxt or Next if you imported a global object, which is ultimately what these are!
@jesper.ordrup
@jesper.ordrup 5 ай бұрын
Agree 🎉
@cory2300
@cory2300 5 ай бұрын
omg why is this not blasted on the SK docs. Thank you for this video honestly - you saved my future ass.
@Huntabyte
@Huntabyte 5 ай бұрын
There is a whole page dedicated to it, but perhaps it should be more obvious! kit.svelte.dev/docs/state-management
@supbra1
@supbra1 5 ай бұрын
Not sure if I understand - what is the unsafe way? Did you show it in the video?
@Huntabyte
@Huntabyte 5 ай бұрын
At the beginning. Exporting a global `writable` store and importing to various modules/components!
@stoched
@stoched 5 ай бұрын
I understand everything you're saying in the video, but something you didn't explain is why is it that using setContext/getContext fixes this global state issue? Because in my mind when you set the context key to some constant then it would be the same reference for everyone on the server? So what makes setContext uniquely preserve the state per user and prevent it from leaking between each other?
@Huntabyte
@Huntabyte 5 ай бұрын
I apologize for not clarifying further! It's not that `setContext` uniquely preserves the state per user, its that the state isn't able to be referenced globally, since it's initialized inside of (2) closures in this example - the `` tags, as well as the `setUserState()` function. You can't reference something _within_ those functions from outside of them, unlike a global object or global writable being exported from some module.
@stoched
@stoched 5 ай бұрын
@@Huntabyte Hm I think I'm following. Are you saying if you have UserA and UserB: If UserA has already been on the site for awhile then the root +layout has already ran (which sets the context). That won't re-run at all. But if UserB visits the site then that will trigger +layout to render on the server side which re-initializes everything inside that context? Since it's a new instance of the context happening each time +layout is rendered on the server it will always be unique for each visitor ( and properties won't bleed into other users state, etc). Is that correct?
@Huntabyte
@Huntabyte 5 ай бұрын
Yes but the context in and of itself isn't what's helping here, it's the fact that we have the creation of that store being done inside of a function, and the state itself isn't being exported from a global module. A good rule of thumb is to never put the keyword `export` in front of some state that you wouldn't want potentially persisted between requests.
@stoched
@stoched 5 ай бұрын
@@Huntabyte Makes sense! Thanks for taking the time to explain I appreciate it!
@peppi69
@peppi69 5 ай бұрын
Thank you but I have a problem with the context API? If i understood it correctly it only updates on +*.svelte components. So for me i have a Nav.svelte component which is importet to +layout.svelte but the getContext inside of the Nav component doesn't get updated, but simply using a global store works fine. Would i need to get the context in the +layout.svelte and pass it to the Nav?
@laztheripper
@laztheripper 5 ай бұрын
Because on the server side, the global store you created on the first request to the server will still be there. It doesn't get deleted after the request. So the next person that makes a request where that store is included, and maybe this user is not logged in and the store is not overwritten, then they would receive the existing store with the previous user's details. Not to mention, if you have 1000 requests per second, and say each one of them updates the store, then on the server that single store will update 1000 times, triggering all of the code that listens for those changes in all of the requests currently being handled. This is how JS works, if you import x from y, whatever that file exports will remain. If what's exported is a store, then the state of that store is shared across all requests that use the store.
@d4yno
@d4yno 5 ай бұрын
Whats the benefit of using classes?
@windar2390
@windar2390 5 ай бұрын
classes can bundle a bunch of methods and stores. of course the same is possible with object factories. but classes are "cleaner" and work better with vsc-intellisense. (i worked first with object factories, but got annoyed with not working intellisense. since i work with classes, i dont have these problems anymore.)
@ScriKidding-eg6vn
@ScriKidding-eg6vn 5 ай бұрын
damn this guy is brilliant
@benfrese3573
@benfrese3573 5 ай бұрын
lol that thumbnail (espeically like the little huntabyte logo)
@Huntabyte
@Huntabyte 5 ай бұрын
I'm glad you appreciate it 😂
@derpenz5376
@derpenz5376 5 ай бұрын
Do we even need Stores in svelte 5?
@Huntabyte
@Huntabyte 5 ай бұрын
Yes, but rarely.
@laztheripper
@laztheripper 5 ай бұрын
What I do is still use global state, but I never update the SSR values of these stores after initialization with sensible defaults. This means all my pages can be SSR rendered, with for example no current session active. This works better than expected because client states should never change on the server anyway, and I've wrapped the server side versions with a function that throws an error if the server side state ever changes. I have a big problem with the context api. All of the code you've shown can only be ran at the root of a .svelte component file. Meaning, it's impossible for regular JS classes and libs to import the global state. You might think sure, but then you can update a store with the current context, but you've just reproduced the same issue from before. I keep running into this issue, that I really need something like the $page store that is per request, but accessible from anywhere and/or editable by my own code.
@Huntabyte
@Huntabyte 5 ай бұрын
You'd have to be calling those functions somehow within your components though right? In that case you can pass the store into those functions and handle it that way! Of course its a matter of preference and it's nice that you have the exception being thrown to avoid any issues!
@laztheripper
@laztheripper 5 ай бұрын
In simple cases, yes you'd use the store directly. But in more complicated sites, the state is probably consumed by multiple other classes, and then those might be visually represented in a component. So those 2nd order classes need a way to access state that doesn't depend on a component fetching context.@@Huntabyte Note that I've pushed svelte(kit) maybe a bit past what it was designed to do. I built an ecommerce site with websockets, CF public caching, internal request chaining so that even the site itself gets data from its own apis, rolled my own auth with email/pass (with email confirmation), google / discord oauth, SEO, dynamic sitemaps and xml feeds, and a lot more. So I've ran into most of the sharp edges by now, and one of them is global state.
@tuvshinbayartuvshinzul8489
@tuvshinbayartuvshinzul8489 5 ай бұрын
TLDW; always use it with Context API if you need a global state.
@Huntabyte
@Huntabyte 5 ай бұрын
Wouldn’t this technically be TLDW?
@tuvshinbayartuvshinzul8489
@tuvshinbayartuvshinzul8489 5 ай бұрын
yes 😅
@tuvshinbayartuvshinzul8489
@tuvshinbayartuvshinzul8489 5 ай бұрын
edited
@omomer3506
@omomer3506 5 ай бұрын
Okay can someone explain the {children} =$props i haven't seen it in sveltekit
@laztheripper
@laztheripper 5 ай бұрын
It's just how you get variables you passed to a component in svelte 5. It's really just destructuring.
@windar2390
@windar2390 5 ай бұрын
this has nothing to do with svelte. this is javascript object destructuring.
@omomer3506
@omomer3506 5 ай бұрын
​@@laztheripper Am not talking about the destructing itself, but what is the $props() function i havent seent it
@omomer3506
@omomer3506 5 ай бұрын
​@@windar2390not talking about the destruction but $props() most $ variables are native to svelte since it compiles them, , and i haven't seen this function before
@laztheripper
@laztheripper 5 ай бұрын
As I said it's how svelte 5 passes your component variables. If you aren't on svelte 5 then it's normal you haven't seen it. within MyBanner, you'd get the title from $props() instead of export let title;@@omomer3506
@SilvestreVivo
@SilvestreVivo 5 ай бұрын
I think this doesn't prevent the main problem: layout.server is loaded each time you navigate in SSR. Besides that, you have the $page.data object to collect everything from layout.server and have it available among all components in SSR.
@Huntabyte
@Huntabyte 5 ай бұрын
The store is created inside of a closure so it does in fact prevent the main problem. Additionally, $page.data also uses the Context API under the hood, see: kit.svelte.dev/docs/state-management#using-stores-with-context
@Hugos68
@Hugos68 5 ай бұрын
How is the server side layout rerunning relevant to the context API, the context API is only client side, so it can never leak to the server
@SilvestreVivo
@SilvestreVivo 5 ай бұрын
@@Huntabyte it doesn't matter if it is inside of a closure. The layout.server.ts file will run each time you navigate, so it will fetch from the API the data not only once. For the second thing, if $page.data solves the problem, why do we need to create again the same? My comment is about an app I am building now and I am struggling with this too.
@SilvestreVivo
@SilvestreVivo 5 ай бұрын
@@Hugos68I didn't say anything about that. I am talking about something totally different.
@nicky-hajal
@nicky-hajal 4 ай бұрын
@@Hugos68 Just to clarify: if the site is running SSR, the context API does run on the server and is the crucial element that prevents data from leaking between requests.
@meaningmean
@meaningmean 5 ай бұрын
Thanks
@Huntabyte
@Huntabyte 5 ай бұрын
You're welcome!
@windar2390
@windar2390 5 ай бұрын
Thats exactly how I do it. :) But I dont put stores into context, but a main-class that contains all my stores and handlers. export let data: LayoutData; const main = new Main(data); setMainToContext(main); in other components: const main = getMainFromContext();
@laztheripper
@laztheripper 5 ай бұрын
Meaning you have to getContext() anytime you need this data. Which can only be done at the root of a component. How do you import your global state into other .js files (not components)? Because I haven't found a clean solution for that. Svelte really needs a per request store/api like the $page store, but that is accessible outside components and editable by our own code.
@windar2390
@windar2390 5 ай бұрын
​@@laztheripper i dont know what exactly you mean with global state. all my user-data is saved in the main-stores. all my static data (for every user the same) is saved in normal js/ts-files. if you need access to user-data there are only 2 ways. 1) you get the data in the component and pass it down to your functions 2) you put your functions in the main-class as well. (my choice) when i have to mutate userdata, my code looks like this: const main = getMainFromContext(); const lists = main.lists; lists.addNewList({listName: 'Oh, hi Mark!'}) const paraController = main.paraController; paraController.setDarkMode(1) the nice part is, as soon as "main" is loaded, you are "free". every function has access to every data. but there are some tricky situations in hooks.server.ts, where main never will be loaded.
@Huntabyte
@Huntabyte 5 ай бұрын
You can pass the stores as an argument to whatever function your calling and it will work the same as importing :)@@laztheripper
@Huntabyte
@Huntabyte 5 ай бұрын
This is a brilliant way of handling this!
@laztheripper
@laztheripper 5 ай бұрын
Which means again the source of the call has to be a component that gets the context. If for example I have websocket messaging class (real case btw), and I want to use global state in that class when a message is received, I need to have a component somewhere to get the context and hoist it into my class instance so that I can use it later, and then I have to get() on the store to access the data, which does a subscribe() and unsub() after which is not good. I've coded solutions for this ofc, but they aren't simple and I shouldn't have to. Alls I'm saying. Forcing everything through components, when a lot of code is purely transactional makes no sense, a lot of it doesn't have a visual representation, and I shouldn't be forced to create dummy components to make my state work.@@Huntabyte
@nomadshiba
@nomadshiba 5 ай бұрын
i always stick with PageData and ActionData. dont need to invalidate anything manually because i just use form actions with `use:enhance`.
@Huntabyte
@Huntabyte 5 ай бұрын
This is perfectly fine for a lot of use cases! When you want to start adding custom store logic/have really really reactive apps, you'll likely reach for your own stores!
@Huntabyte
@Huntabyte 5 ай бұрын
Also, the `$page` store actually uses the Context API under the hood!
@brookesstephens
@brookesstephens 5 ай бұрын
Definitely made that mistake!
@Huntabyte
@Huntabyte 5 ай бұрын
As have I!
@seanknowles9985
@seanknowles9985 5 ай бұрын
Also how are you using $props when svelte 5 hasn't been released yet?
@Huntabyte
@Huntabyte 5 ай бұрын
I'm using the prerelease version to start getting experience with it and trying to find any bugs along the way to raise to the team!
@seanknowles9985
@seanknowles9985 5 ай бұрын
why are you mixing functional and class patterns?
@tobias3581
@tobias3581 5 ай бұрын
Thanks for sharing. Kit is opinionated and nice in theory but, low quality types, weak route validation, and offering a backend (kit) to a reactive systems (svelte) with such footguns. Kit is so opinionated in code organization while simultaneously not taking responsibility for its intended effect. Kit is like bathing in a pool of pee and being told to stay in the corner
@zzonawav
@zzonawav 5 ай бұрын
curious to know what your go to JavaScript front end is.
@tobias3581
@tobias3581 4 ай бұрын
@@zzonawav they all suck 😂 on paper, the new direction of solidstart is on point, but historically little popularity and weak typing are concerns. Remix is pretty nice in react land. I still think Vue is the best across the board in terms of DX, typings, productivity, ecosystem, tooling. Nuxt is a bit magic but lots of nice things, so I’d go with Nuxt. If you have loads of time and want the best then solidstart or leptos in rust -
@smen66
@smen66 3 ай бұрын
Has the state file to be called state.svelte.ts or could it be also state.ts? Is there a difference?
Svelte UI Libraries Have Leveled Up
12:14
Huntabyte
Рет қаралды 51 М.
Protect SvelteKit Routes with Hooks
21:10
Huntabyte
Рет қаралды 52 М.
ДЕНЬ РОЖДЕНИЯ БАБУШКИ #shorts
00:19
Паша Осадчий
Рет қаралды 4,9 МЛН
Why Your Load Functions are Slow
8:24
Huntabyte
Рет қаралды 19 М.
Best UI Library for Svelte
16:13
Huntabyte
Рет қаралды 103 М.
INSANE ComfyUI Node writes new Nodes with AI (and Local LLMs)
21:11
Understand How Data Flows Through SvelteKit
25:59
Joy of Code
Рет қаралды 17 М.
The Problem with Using Layouts for Auth
7:10
Huntabyte
Рет қаралды 46 М.
Loading Data in SvelteKit (+page.js & +page.server.js)
14:22
Huntabyte
Рет қаралды 72 М.
i didn't know these svelte tips
18:56
Nev the Dev
Рет қаралды 1,7 М.
Function Calling in Ollama vs OpenAI
8:49
Matt Williams
Рет қаралды 24 М.
ДЕНЬ РОЖДЕНИЯ БАБУШКИ #shorts
00:19
Паша Осадчий
Рет қаралды 4,9 МЛН