Tiny PWAs and why I keep building them
Published: 2019-10-30 00:19:24

---
title: Tiny PWAs and why I keep building them
published: true
date: 2019-01-31 16:00:00 UTC
tags: 
canonical_url: https://justinribeiro.com/chronicle/2019/01/31/tiny-pwas-and-why-i-keep-building-them/
---

I did not set out to build tiny progressive web apps. Well, that’s not true; I set out to build PWAs that solve particular problems in my life, which ended up being tiny. Then it just became fun.

You see my car, a 2005 Prius, has a terrible glitch in the dashboard where the dash simply doesn’t work. No speedometer, no gasoline gauge, nada. I can fix it by doing some solder work, but that require me to tear down the dash which is rather time consuming.

My kids also have a particular issue; they like to sleep in the dark but have a furious appetite for Monica or myself to read to them. A lot. They’re at the Harry Potter stage, which means you’re _reading_. This is serious work and a lot of joy. They love the little reading LEDs I make, which means they go missing on a daily basis.

Both the above cases would lead one to say “surely there is a app for that!” A quick look leads to speedometer apps with ads and 30MB download weight, and simple screen light that also have ads that weight in at 5MB.

I collectively sighed. None looked reasonable to me. Maybe I was grumpy. Maybe I don’t trust things in app stores much anymore. It’s a mixed bag.

Which lead me down the rabbit hole: how quickly can I build these sort of apps as PWAs? Do I have enough API surface on the web platform?

For the speedometer, we can look at the [GeoLocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation). The GeoLocation API has a Position interface, which contains a Coordinates object, coords. This Coordinates interface contains not only things you might expect (latitude, longitude), but also contains a property called speed, which is represented as the device velocity in meters per second. Chrome on Android returns this prop with very little effort, at which point it’s just a matter of some quick math to do the mph/kmh conversion.

![Running my speedometer PWA](https://storage.googleapis.com/jdr-public-imgs/blog/20190131-car-dashboard-pwa.jpg)

That said, both the speedometer and the reading light have a problem; how do we keep the screen on? Luckily, there’s a new API we can play with called the WakeLock API.

The [WakeLock API](https://www.w3.org/TR/wake-lock/) allows us to prevent our device from going into power saving mode and generally prevent the screen from turning off using a simple bit of code:

```
const startWakeLock = () =\> { try { navigator.getWakeLock("screen").then((wakeLock) =\> { appOpts.wakeLock = wakeLock.createRequest(); }); } catch(error) { // no experimental wake lock api build } }
```

Now, this API is subject to change ([comments welcome](https://github.com/w3c/wake-lock/issues)), as we’re still trying to sort out what the permissions model looks like among other things. You can also read an article about it Pete LePage recently wrote on, _[I’m Awake! Stay Awake with the WakeLock API](https://developers.google.com/web/updates/2018/12/wakelock)_. But the API, when flipping the flag within Chrome, works as expected giving me the ability to build out said PWAs.

Along those lines, the experimental [AmbientLightSensor API](https://developer.mozilla.org/en-US/docs/Web/API/AmbientLightSensor) behind the chrome://flags#enable-generic-sensor-extra-classes also allows me to detect when it’s dark outside, allowing me to have a proper low-light style with very little code effort:

```
const startAmbientSensor = () =\> { if ('AmbientLightSensor' in window) { navigator.permissions.query({ name: 'ambient-light-sensor' }) .then(result =\> { if (result.state === 'denied') { return; } const sensor = new AmbientLightSensor({frequency: 0.25}); sensor.addEventListener('reading', () =\> { if (sensor['illuminance'] \< 3 && !appOpts.dom.body.classList.contains('dark')) { appOpts.dom.body.classList.toggle('dark'); } else if (sensor['illuminance'] \> 3 && appOpts.dom.body.classList.contains('dark')) { appOpts.dom.body.classList.toggle('dark'); }; }); sensor.start(); }); } }
```

The end result, smoothly switching based on our lumens, is quite pleasant:

![Day/night mode via the AmbientLightSensor API](https://storage.googleapis.com/jdr-public-imgs/blog/20190131-day-night-mode.png)

The end result [speedometer pwa](https://speedometer.pwa.run/) is astonishing tiny; just 1.7KB for the speedometer and 800B for the reading light. The service worker is tiny as well, as it doesn’t have to work too hard as we’re not dealing with anything but a version index file for the most part. You can grab a look at the source code on Github: [justinribeiro/speedometer-pwa](https://github.com/justinribeiro/speedometer-pwa).

The [screen reading light](https://readinglight.pwa.run/) is similarly of small size, also available on Github: [justinribeiro/readinglight-pwa](https://github.com/justinribeiro/readinglight-pwa).

These two tiny PWAs are really just the tip of my tiny PWA stash; I’ve started making all kinds of them. Getting them all written up and pushed to Github, well, I’m still working on that. It was the holidays, so sue me. :-)

In the mean time, try some new web platform APIs and give the tiny PWA writing a spin. You just might find some joy in it! 🎉