A realistic SSR ready web app with Svelte + Sapper + StarWars API
Tags: svelte, javascript, webdev, sapper
Published: 2020-01-07 20:19:35

How I built a SSR ready [Star Wars app](https://keen-clarke-08ba4f.netlify.com/) 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.
{% youtube AdNJ3fydeao %}
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.

{% gist https://gist.github.com/crup/44b24909f35d1f4a5cec314481d8f374 %}

Adding `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.

![Lagging effect](https://i.imgur.com/hFNopCO.gif)

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.
{% github crup/svelte-ssr-swapi no-readme %}
```bash
$ 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.
{% gist https://gist.github.com/crup/a7a5a4447b45ebcd3d63fd6570c00668 %}

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:
{% gist https://gist.github.com/crup/5d9b7820c0fafefb9ed3c58ff325ed1b %}

On your page level component set `isSSR` to `false` and resolve `cards` if it's a promise. Setting `isSSR` to `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.

{% gist https://gist.github.com/crup/17fc08b8aae2a5de4b756c4a1ebab02f %} 

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.

{% gist https://gist.github.com/crup/9e59ad466609a075fd7093e5cb01eb92 %} 

The final version is in `master` branch and it looks like this:
![Final result](https://i.imgur.com/HQuCLuc.gif)


###[Demo](https://keen-clarke-08ba4f.netlify.com/)

Disclaimer: 
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. :)

{% github crup/svelte-ssr-swapi no-readme %}