SPA with 4x100% lighthouse score - Part 2: Building an app
Tags: javascript, svelte, webperf, webdev
Published: 2020-03-24 20:06:54

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pj1bz1007mekhs37j00u.jpg)


### Setting up the app

In last part we decided to go for **JS**, **Svelte js** framework/compiler and **Sapper**. If you want to know more about my reasoning, why I picked these technologies, and you haven't read my previous article, [go and read it](https://dev.to/rezi/spa-with-4x100-lighthouse-score-part-1-the-tech-stack-gac) ;)

This time we will attempt to build together a demo app and hopefully reach our goal. In this part of the serie, we just finetune the Sapper *hellow world* app to max lighthouse score. In next part we'll build on top of our skeleton and create a fancy weather forecast app. 

Beware, this is not an article about Svelte/Sapper, so we will go through the implementation in rather fast pace. But don't worry, if you dont know these technologies, I'll guide you through.

Be sure you have `node js`, `npm` and `npx` installed. Now let's get a *hello world* Sapper app running. 

```
npx degit "sveltejs/sapper-template#rollup" lighthouse-app
cd lighthouse-app

npm install
npm run dev
```

Our Sapper app is now running on `http://localhost:3000`
If we run the lighthouse audit now, we are in green numbers but we won't get 4x100%. There are more reasons for getting 100% score:
 
1. Page is server rendered every time we hit a url
2. CSS assets are loaded via `<link>` element
3. Image is not in future format (webP)
4. Image doesn't have optimal size
5. Page metadata are missing
6. Missing apple touch icons
7. App is not running neither on http2 nor https
8. Http is not redirected to https


 
Let's fix them one by one:


### 1) Page is server rendered all the time we hit a url

This one is easy, Sapper has another set of commands for exporting web app as a set of static pages and assets. Just run the build and commands like this instead of the one metioned above

```
npm run export & npx serve __sapper__/export
```

Done app is running on `http://localhost:5000` and the performace is already rated to 100% ;)

### 2. CSS assets are loaded via `<link>` element

The `<link>` behavior is not that bad, css files are made per component. So once you hit other page with same component, you already have the CSS cached by service worker. The default behavior seems to be good for apps with heavily repeating components, not for our app ;) Probably better for us, in terms of speed, is lighthouse's proposed way of injecting crucial css inline to the `<head>` element and thus avoiding the render-blocking request for sepearate css files. Let's change it. 
Open `rollup.config.js` and change `emitCss` flag in svelte plugin to *false*.
There is one more render blocking request and it is the `global.css`. Go to `src/template.html` and comment it out (we will maybe use it later).
For now lets use some base css directly in `template.html`. Add following code above the commented stylesheet link:

```html
     <style>
      html {
        box-sizing: border-box;
        font-size: calc(14px + 6 * (100vw / 1280));
	  }
	  
	  @media screen and (min-width: 1280px) {
        html {
          font-size: 20px;
        }
      }

      body {
        margin: 0;
        font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen,
          Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
        line-height: 1.5;
        color: #333;
      }
    </style>
```
Congratulations, you just made your app half way responsive.
 
The weird font size calculation is my minified version of something called *poly fluid sizing*. your base font size now scales from 14px to 20px as the screen grows to 1280px. To whatever you apply size in rems, will scale with it. 1rem is now something between 14-20px depending on screen width.

Rebuild the app and voilà. Even with the regular `npm run dev` we get 100% performance.


### 3) Image is not in future format (webP)

Just take the image `static/great-success.png` and turn it first to jpg (so we loose alpha channel). Then convert it for instance with [webP convertor](https://webp-converter.com/). Copy the image to the `static` folder and adjust its html in `src/routes/index.svelte` accordingly.

### 4) Image Doesn't have optimal size

Not only it has wrong size, it is also one and only size the img tag offer. We can do better, we will use `<picture>` with `srcset` tag. Go to [responsivebreakpoints.com](https://www.responsivebreakpoints.com/) and upload our webP img, set max resolution to 400 (it is the image max size it can get in our app). Save images to `static` folder. Replace old `img` tag with new `picture` one, which was generated by the tool. Done.

### 5) Page metadata are missing

Go to `src/routes/index.html` and any other page(route) you want to optimize and add following metatag into the `<svelte:head>` tag.

```html
 <meta
    name="description"
    content="Welcome to sapper app" />
```
Now we get 100% SEO rating on every page where we added the meta description

### 6) Missing apple touch icons

Grab some nice simple icon and process it with [realfavicongenerator](https://realfavicongenerator.net/).
Copy generated code to `src/template.html` and files to `static` folder

### 7) App is not running neither on http2 nor https

Now it is time to move our app to the internet. We could also run our local server with npm spdy server and self signed certificates. But it won't prepare us for real internet conditions. We will deploy our app to [Netlify](https://www.netlify.com/). it is free for testing purposes, it is fast, works as CDN, and even provides serverless functions and auth middleware.

Easiest setup is to create netlify app from github repository. Create a repository on github and push your *lighthouse-app* to it.
Now sign up for [netlify](https://netlify.com/). In your netlify *site* page, click **New site from git**. Once you are in step 3, you will be asked for *Build command* and *Publish directory*. Fill first with `npm run export` and second with `__sapper__/export`. Then click **Deploy site**

Each time you push to a chosen branch in github, netlify hooks into it and builds and deploys a new version.

### 8) Http is not redirected to https

This is already done, as Netlify provides https, http/2 and redirects out of the box.


Now we only need to measure the results. Copy the url netlify generated for your web app. For me it is [https://eloquent-dijkstra-d8bd7b.netlify.com/](https://eloquent-dijkstra-d8bd7b.netlify.com/). 

Now go to the new online measuring tool (lighthouse) [web.dev](https://web.dev/measure/). We should measure by this one, not by plugin in chrome or dev tools. The web.dev tool give you more stable results, not influenced by quality of your internet connection and your computer's power.

Here are the results, not bad, considering, it took us 10 minutes from start to end. 

![Lighthouse audit results](https://dev-to-uploads.s3.amazonaws.com/i/tt39iz5gjedxhjz4paaf.gif)

![Lighthouse audit times](https://dev-to-uploads.s3.amazonaws.com/i/q02gb7x8jz3afa582sjg.png)


We have a skeleton for a future app. We are backed by full featured component based framework with all the things like 2-way-binding, state management, routing, animations etc. 

In the next part of this serie we try to turn this *hello world* app to a more real-world app example: a Weather forecast app. We will see whether we are able to keep our perfect score with a growing complexity and connection to an external API.
In the meantime you should go and learn some basics about [svelte](https://svelte.dev/) and [sapper](https://sapper.svelte.dev/). 

See you next time ;)