I've been building an application in Svelte/Sapper that I will release in the near future. Given my previous postings of Svelte/Sapper and use of Svelte for the blog and other applications, I think I can say I am a fanatic. Ok, maybe more of a very very eager user of excellent software.
With that a way, no software is deemed unworthy of critique yet. Let's talk about that.
Layout. This is a Sapper router feature. There is a _layout.svelte file used in Sapper that is included in all routes. I personally think it is tersely/badly named, but the name is a reasonable choice among others. You can create sub _layout.svelte files in nested routes to add on to the layout wrapping. Each of my pages have a "Layout" Element instead, so I can pick and choose how the page's content layout is presented. Sometimes a header is needed and other times nothing is needed. If I had to name the element, it would probably be _presentation or _page-context or something. I'm sure _layout exists for reasons i haven't looked in to.
- Why segment is not a globally available property like how window, document, navigator are is a mystery. Why should only _layout know this? I'd be fine if sapper's page store had this property. I instead make my own global store and populate it from the root _layout.
Bootstrapping + Splash. I used to do bootstrapping in client.js. Well, now I do it in my own "Layout" files. I keep a global store for splash state, so that is can be marked as showing or not showing by the by the particular "Layout" file. I feel like there needs to be a hook for application init in Sapper. One that accepts async function properly unlike onMount: https://github.com/sveltejs/svelte/issues/3641
Authentication. Authentication story for Svelte/Sapper is honestly not fleshed out. I naively tried to use _layout for this. I was used to React where I could define a set of (un)protected routes. When auth state changed, the protected routes would come into play and if the current route I was on was in the protected routes then a protected version would display which mean different page layout. With Sapper particularly, I have a login function that sets local storage/cookies and does goto a fixed route (temporarily) on success. Bootstrap script when run would check if the user is authenticated still before letting go of the splash screen and pushing them to a place where they can login ore proceed to the intended endpoint.
Store (Un)subscriptions + onmount([a]sync) + memory leaks. So one has the choice of reactive statements which auto (un)sub to Svelte stores or use the functions yourself wherever you want. Given that the subscription functions will run on first invokation, I desire them not to run on the server side, so I place them in onMount(async). The question then is how to unsubscribe when component is destroyed only on client side. Well, onMount(sync) will call the function you returned to it when it called your callback. onMount(async) instead gets a promise, so that is a dud (https://github.com/sveltejs/svelte/issues/3641). You'll end up having to create variables or array of unsub functions that will have to be called at destroy time. Since some of your subscriptions may have happened after the async, now you have to figure out how to subscribe without running the first time, so that you can prevent a memory leak in case the async function does not finish before a user decides to navigate away.
- I have an idea of how to solve it for my own case and I'll see what I can do. It would consist of store a route context per subscription, so that when the context is destroyed any more subscriptions after the fact would be auto unsubscribed as to not cause memory leaks. Only an idea right now. Probably too complicated.
- It would be better to schedule the async in a queue and when the component is going to be destroyed schedule the unsubscriptions after the onmount(async) is done. It is a variation of the previous idea which uses promise queues rather than a context map. Looks like a simper idea at first glance.
Yeah, I just thought of these potential solutions right now. It happens.
No way to force updates when attr={func($store)}. I consider this to be a computed property. If I say $store.update($store) then I expect the computed property to be rerun. Instead I use a map/object now where I can force an update with self assignment. Self assignment is pretty weird to see, so I include a comment for each one. Property is now attr={computedMap[$store]} instead.
Updating query params needs a good story. I have my own functions that update the query params by adding/updating or removing individual params along with a choice to replaceState. I know it is a SPA and all, but I'd like to have params that are per-selected by users, so they are shareable. If a filter is removed then the param should be removed from the page query.
Overall, I love Svelte and Sapper and these libraries are only in their infancy. 😀
Zed Shaw has things to say about Svelte too: https://twitter.com/lzsthw/status/1139699325729042438