How I built a SSR ready Star Wars app with Svelte in just few hours.
Svelte - As everyone know it's a "new" cool kid in the block. If you are still living under the rock, I recommend you to watch this presentation by Rich Harris - the creator of Svelte.
Sapper? Sapper is a
Next.js equivalent for Svelte. It creates a bare-minimum boilerplate with routing, code-splitting, service worker and what not.
Recently I decided to try my hands on Svelte to create an app that supports both server side and client side rendering with those fancy shimmer effects.
So, let's get started.
Implementing SSR in Sapper is fairly simple and straight-forward. All you need is this code-block in your svelte files.
context="module" in a script tag with an exported preload function implements SSR and CSR with pre-fetch(optional) like waving a magic wand. But there's a problem.
When I click or hover(with
rel=prefetch) on a menu item, Svelte tries to fetch the route chunk and resolves the api calls and only then navigates to the next page. It gives an impression that the app is either frozen or lagging which can be a frustrating user experience.
Clone the repo down below and checkout to the problematic commit hash(
4bb9d18) to experience the issue.
$ git clone https://github.com/crup/svelte-ssr-swapi.git $ cd svelte-ssr-swapi $ git checkout 4bb9d18 $ yarn && yarn dev
How to fix this? With only a couple of hours of experience in Svelte, I don't know the right way but this is how I solved it me.
Create a Svelte store and define a key which will be an identifier for for distinguishing if the page is SSR or CSR.
In your routes file, instead of resolving the promise and returning the resolved response in
cards key, read the SSR state and and return promise if
isSSR is false.
Here's the boilerplate:
On your page level component set
false and resolve
cards if it's a promise. Setting
false on first client-side render will enforce script tag with
context="module" to return a promise instead of response.
With this approach we can now resolve apis on client side, show loaders/shimmers without any lag.
Now comes the worst part - rendering this list items. Since we now have an array(server-side) and a promise(client-side). I had to write handlers for both array and promise.
This is my very first attempt at Svelte and chances are that I may have done massive blunders like improperly accessing/updating/unsubscribing store, duplicating code in rendering cards and routes. There's a also a room for refactor in final branch. So, use this code at your own risk.
If there's a better way to achieve the same, feel free to create a PR and suggestions are welcome. :)