API Simulator allows you to setup any number of static routes (URLs) on the host it runs on, allowing you to test a static JSON response. Might come in handy when building prototypes or sample apps:

API Tester has been built in ~12 hours as part of an internal Service Worker hackathon, is nothing revolutionary and and is definitely not ready for production (only been tested in Chrome Canary) – but hey, you won’t use it for production code anyway ;)

More interesting than the outcome might be the path that got me there. The tech being used is a combination of Service Worker, MessageChannel and Promises. Here are some interesting gotchas, in no particular order:

Reloading a Service Worker is not trivial (…without Workspaces)

Reloading a page requires hitting F5. Reloading Service Worker requires you to:

  1. Make sure caching on the SW file is disabled by your development server, or the SW will be cached for 24 hours
  2. Open chrome://serviceworker-internals/, tick the checkbox next to “Opens the DevTools window for ServiceWorker on start for debugging.”
  3. After making changes to SW, reload your current client (tab connected to it), should bring up new, second DevTools window with new instance of service worker, saying it has been installed (but it’s not running yet!)
  4. Close all other tabs that could interact with the worker currently running
  5. Shift-Reload the current tab you’re in, resulting in SW being ignored / not used
  6. Reload tab a second time, this time normally
  7. New version of service worker should now take over, old version should die
  8. ???
  9. Profit

OK OK, step 8 wasn’t needed, but everything else is brutal reality today. There are good, complicated reasons, but that doesn’t change the fact that it is a pain in the butt. Unless, of course, you’re using DevTools’ Workspaces (mapping your local filesystem to the running worker), in which case the workflow is dramatically simplified:

  1. Make change to SW
  2. Profit

No, really. When you make a change to the SW now (whether in your external editor or directly in the DevTools window), DevTools will find out about said changes, hot-patch the currently live Service Worker with the changes (reporting “Recompilation and update succeeded.” in the console), with no need for you to reload the client or the worker. It’s magic.

Bi-directional communication is tricky (..without MessageChannel)

Sending events through postMessage from the client to the worker is pretty straight forward, but the other way around is not. In my case, I wanted the Service Worker to store all routes in his own IndexedDB database, and let the clients consume and manage that data. But from the Worker itself, you don’t have a client object to reply back to, so what do you do?

You use a MessageChannel. A MessageChannel is basically a tin can telephone. You create an instance of it on the client, and said instance holds two ports (two tin cans). One port (port2) is being sent to the worker in a normal message, which establishes the link between both, the other port (port1) belongs to the client. Both ports have a postMessage function and take an “onmessage” function, so now that you have a tin on both sides, both can communicate freely. Problem solved.

IndexedDB is crucial pain

IndexedDB has the most convoluted crap API I’ve seen in a while, and you wouldn’t imagine the things I’ve seen. It’s worse than the drag & drop API. After a few hours with it, my anger turned to disbelief – I mean, what where they thinking? How could this ever end up in browsers? Why is there no war? Have I missed something?

All I needed is a simple key value storage. LocalStorage, you say? Meep. Try again. There’s no localStorage in Service Worker. Having never worked with IndexedDB before, I naively thought “surely they thought about how to solve the most simple use case in a satisfactory manner”, so I expected something like localStorage.setItem, just async. You know, like asyncStorage.setItem().then(..). What was two lines of code in localStorage became a 100 lines in IndexedDB. Seriously.

To those that argue that it’s been built as “well performing, underlying platform feature to build upon”, you are the problem. It’s unfortunate that I have to remind you that you are building a product for web developers. If your product is not usable, you failed.

Ending on a high note

Service Worker shows that it is possible to create an API that is both highly flexible and low level, yet very user friendly and effective. With the exception of needing to mess with IndexedDB, working with Service Worker has been surprisingly fun and empowering, even in its early state of implementation.

Get on board!