Debugging PWA’s locally – or how to get a angular 100% Lighthouse score

Yesterday at the @NgStuttgart Meetup, we had a really good time with two talks:

  • “What’s new in Angular 8” (David Muellerchen – GDE – @webdave_de – webdave.de)
  • “Improving UX by performance with Angular” (Steffen Stähle & Florian Tischler – @Steffen_Staehle & @floriantischler)

During the talks we came across a little node tool called local-web-server it helped me a lot when debugging Angular PWA’s locally. It offers

Build a angular PWA

First of all I’ve created a simple angular application (including the new ivy rendering engine, because I can):

➜  npm i -g @angular/cli
➜  ng new pwa --routing false --style css

And added PWA support afterwards:

➜  ng add @angular/pwa

Now we need to prepare some small additions to our application code.

In our index.html add the following two lines between to the head of our html document:

<meta name="Description" content="Put your description here.">
<link rel="apple-touch-icon" href="/assets/icons/icon-192x192.png"/>

In our tsconfig.app.json add the following part, to enable rending with the new Ivy render engine:

"angularCompilerOptions": {
  "enableIvy": true
}

And finally build our PWA:

➜  ng build --prod

Now let’s go and get that Highscore.

Setup the local web server

I’ve installed the package local-web-server globally:

➜  npm i -g local-web-server

This gives us a new CLI command “ws”, which serves the current folder on port 8000. It supports HTTPS and HTTP/2 out of the box. But to get a green pad icon in our browsers, some more preparation steps have to be done.

They have an awesome wiki on GitHub:

https://github.com/lwsjs/local-web-server/wiki

I decided to go with the “How to get the “green padlock” using the built-in certificate” way on my development MacBook.

These where the steps I did (have a look at the wiki for more details).

➜  open /usr/local/lib/node_modules/local-web-server/node_modules/lws/ssl/
  1. Open Keychain Assistant
  2. Import the certificate “lws-cert.pem”
  3. Open it and select “Always trust”

Now we are ready to rock!

Lighthouse that thing…

Now we fire up the server with http2 and spa support

➜  cd dist/pwa
➜  ws --spa index.html --http2 -z --port 443

Now fire up your browser of choice (still chrome for me :) and open and see the our app.

https://localhost

Lighthouse

Now let’s check what we got, using lighthouse.

➜   npx lighthouse https://localhost --view

Looks good, but what happened to the PWA part?

Runtime error encountered: Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Details: net::ERR_CONNECTION_REFUSED)

I do not know if this is a Lighthouse or ws bug. But I’ve found a way to get around this issue. When we go to the details we see, that there is a line saying:

Redirects HTTP traffic to HTTPS Error!

So let’s setup a HTTP to HTTPS Redirect using local-web-server, following these steps:

https://github.com/lwsjs/local-web-server/issues/86

Open a new shell and create a file called redirect-everything.js:

module.exports = MiddlewareBase => class Redirector extends MiddlewareBase {
    optionDefinitions() {
        return [
            { name: 'redirectPort', type: Number, description: 'Port which is used to redirect to https' }
        ]
    }
    middleware(options) {
        if (!options.redirectPort) {
            console.warn('\x1b[33m%s\x1b[0m', 'redirectPort parameter is not set, defaulting to 4443');
            options.redirectPort = 4443;
        }

        return (ctx, next) => {
            // Check if protocol is http
            if (ctx.protocol === 'http') {
                // Replacing url with https parameter
                const httpsUrl = ctx.request.href
                    .replace('http', 'https')
                    .replace(options.port, options.redirectPort);

                // Enforcing redirect
                ctx.redirect(httpsUrl);
            }
        }
    }
}

And run the server with:

➜  ws --stack ./redirect-everything.js --redirectPort 443 --port 80

So let’s run another lighthouse test:

➜   npx lighthouse https://localhost --view

Finally all the bits and pieces come together and we get a perfect lighthouse score in an angular ivy app.

Fully interactive after ~1s with 65,7 KB on the first load and a 100% lighthouse score. I would say this is a very good start for your next project.

64,2 KB!
That thing is interactive, BEFORE the browser is trying to get the favicon =)

And finally … it is installable. Good Bye App Stores, you’ve always been that unwanted friend at the party ;)