Progressively enhancing maps

The Session has been online for over 20 years. When you maintain a site for that long, you don���t want to be relying on third parties���it���s only a matter of time until they���re no longer around.

Some third party APIs are unavoidable. The Session has maps for sessions and other events. When people add a new entry, they provide the address but then I need to get the latitude and longitude. So I have to use a third-party geocoding API.

My code is like a lesson in paranoia: I���ve built in the option to switch between multiple geocoding providers. When one of them inevitably starts enshittifying their service, I can quickly move on to another. It���s like having a ���go bag��� for geocoding.

Things are better on the client side. I���m using other people���s JavaScript libraries���like the brilliant abcjs���but at least I can self-host them.

I���m using Leaflet for embedding maps. It���s a great little library built on top of Open Street Map data.

A little while back I linked to a new project called OpenFreeMap. It���s a mapping provider where you even have the option of hosting the tiles yourself!

For now, I���m not self-hosting my map tiles (yet!), but I did want to switch to OpenFreeMap���s tiles. They���re vector-based rather than bitmap, so they���re lovely and crisp.

But there���s an issue.

I can use OpenFreeMap with Leaflet, but to do that I also have to use the MapLibre GL library. But whereas Leaflet is 148K of JavaScript, MapLibre GL is 800K! Yowzers!

That���s mahoosive by the standards of The Session���s performance budget. I���m not sure the loveliness of the vector maps is worth increasing the JavaScript payload by so much.

But this doesn���t have to be an either/or decision. I can use progressive enhancement to get the best of both worlds.

If you land straight on a map page on The Session for the first time, you���ll get the old-fashioned bitmap map tiles. There���s no MapLibre code.

But if you browse around The Session and then arrive on a map page, you���ll get the lovely vector maps.

Here���s what���s happening���

The maps are embedded using an HTML web component called embed-map. The fallback is a static image between the opening and closing tags. The web component then loads up Leaflet.

Here���s where the enhancement comes in. When the web component is initiated (in its connectedCallback method), it uses the Cache API to see if MapLibre has been stored in a cache. If it has, it loads that library:

caches.match('/path/to/maplibre-gl.js').then( responseFromCache => { if (responseFromCache) { // load maplibre-gl.js }});

Then when it comes to drawing the map, I can check for the existence of the maplibreGL object. If it exists, I can use OpenFreeMap tiles. Otherwise I use the old Leaflet tiles.

But how does the MapLibre library end up in a cache? That���s thanks to the service worker script.

During the service worker���s install event, I give it a list of static files to cache: CSS, JavaScript, and so on. That includes third-party libraries like abcjs, Leaflet, and now MapLibre GL.

Crucially this caching happens off the main thread. It happens in the background and it won���t slow down the loading of whatever page is currently being displayed.

That���s it. If the service worker installation works as planned, you���ll get the nice new vector maps. If anything goes wrong, you���ll get the older version.

By the way, it���s always a good idea to use a service worker and the Cache API to store your JavaScript files. As you know, JavaScript is unduly expensive to performance; not only does the JavaScript file have to be downloaded, it then has to be parsed and compiled. But JavaScript stored in a cache during a service worker���s install event is already parsed and compiled.

 •  0 comments  •  flag
Share on Twitter
Published on December 15, 2024 06:55
No comments have been added yet.


Jeremy Keith's Blog

Jeremy Keith
Jeremy Keith isn't a Goodreads Author (yet), but they do have a blog, so here are some recent posts imported from their feed.
Follow Jeremy Keith's blog with rss.