Last year I did a workshop on PWAs for my colleagues at work. And since a workshop naturally requires something to work on, I needed to come up with a little project which should be doable on a single afternoon.
Lucky enough, I discovered that xkcd also provides an API. So my goal was set, I’d build a little XKCD comic viewer to demonstrate web manifests, the service worker life cycle, data fetching, data caching and automated deployment to GitHub pages. (And since I’m a fan of XKCD, I’d end up with something funny for myself!)
While preparing my workshop, I ran into some unexpected problems which turned out pretty useful. That’s what this post is about! :)
Here’s how I imagined the inner workings of my app:
- Fetch meta data of all available posts
- Using the total amount of data, fetch meta data of a random post
- Fetch the post data (image and text)
- Display it
Fetching data should be pretty straight forward:
Access to fetch at 'https://xkcd.com/info.0.json' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
This lead to some problems regarding my workshop:
- I wouldn’t be able to fetch any post meta data1
- It’d also not be possible to fetch image data1
- I could still render stuff, but it would’ve nothing to do with what I wanted to achieve :)
Following the forum post regarding CORS I started to look for existing solutions to my problem and discovered a CORS enabled version of the XKCD API. Using this API instead of the official XKCD one would allow me to cross off two points of my list of open problems:
Fetch meta data of all available posts Using the total amount of data, fetch meta data of a random post
- Fetch the post data (image and text)
The CORS enabled API allowed me to fetch meta data and cache responses using my service worker.
But one problem still remained: How would I be able to fetch image data in a way to properly cache it?
One of the things I wanted to highlight in my workshop was the fact that with service workers it’s possible to intercept and modify any network request. And my problem at hand turned out to be perfect example! I just had to intercept outgoing requests, check whether they are trying to fetch image data from XKCD, and proxy them to enable CORS!
A quick search led me to cors-anywhere, a service which proxies your requests and returns responses with CORS headers attached. After adding the proxy code to my service worker, I could tick the last point of my list:
Fetch meta data of all available posts Using the total amount of data, fetch meta data of a random post Fetch the post data (image and text)
Proxying image data requests worked like a charm. The only thing I noticed was that sometimes, images would load rather slow. Not that big of a problem, but I wasn’t too happy about it.
I started to look for alternatives, but after a while I realised something important. Instead of trying to fix the rather slow data loading, I could use it to my advantage.
I’d build a little XKCD comic viewer to demonstrate web manifests, the service worker life cycle, data fetching, data caching and automated deployment to GitHub pages.
When talking about data caching, this would again be a perfect example! Initial data loading is rather slow, but once we added the response to our dynamic cache, images would load in an instant.
I actually wanted to add a “shake-to-refresh” feature to my workshop PWA, but I didn’t find the time to implement it and it would’ve been beyond the scope of the workshop, anyways. Playing with web APIs is a lot of fun, so I built a little device-motion package and added the functionality when I recently revised this workshop. If you want to use device-motion in your app, you might have a look at it.
My workshop turned out great! I really enjoyed it and according to the feedback of my colleagues, they enjoyed it, too!
Even though I had to take some extra turns it’s really cool to see that the result served as an even better example for my workshop as I initially had planned. Getting kicked out of your comfort zone pays off! :)
That’s the cool thing about workshops. You learn a ton by preparing them, and someone else learns something new once you’re done. So if you ever get the chance to do a workshop, I can only recommend you to take it.
It really pays off in multiple ways!
1 It would still be possible to fetch data using an
opaque response, but opaque responses are not cachable using service workers, so I had to find another way.