Service Workers replacing AppCache, a sledgehammer to crack a nut
About 6 min reading time
If you are into web development, you have probably heard about Service Workers, sometimes referred as “the Application Cache replacement”. I’ve been using and teaching it for a while, and I think we need to talk about it. We are trying to crack a nut with a sledgehammer. We need a Vanilla AppCache new API.
The Application Cache for Offline Applications spec is broken. Anyone with experience using it knows this. That’s why it didn’t appear in the final HTML5 spec recommendation. An AppCache can’t be partially updated, a byte-by-byte manifest comparison to trigger the update seems odd and there are several use cases leading to security and terrible usability problems.
But it’s the only API available today on all modern browsers (yes, IE too) that let us offer an offline experience for the Web. The Chrome team came with a new idea: Service Workers. And we’ve been told several times that Services Worker is the replacement for AppCache. Even Chrome and Firefox are planning to stop support for AppCache in the near future because of this.
Can we replace Application Cache with Service Workers? Yes we can. In the same way we can replace your old CRT TV with a Microsoft Hololens.
I don’t think Service Workers today are really an Application Cache replacement. A Service Worker is a powerful new ability that lets us execute JavaScript in the background outside of an HTML document’s context. Its first use case was to replace the Application Cache spec, but now we know it’s far more capable, being the base for Web Push Notifications, Background Sync and more features in the future such as a Geofencing, Beacon discovery, etc.
I love what’s coming on the web thanks to Service Workers, don’t get me wrong. But I don’t think it’s the smarter solution we can get to replace Application Cache. We are using a sledgehammer to crack a nut.
Understanding the point #
I’ve been working with Service Workers for a while now, inside some webapps, supporting them in a chapter of my future book on Web Performance and teaching about them in several Offline Web and Advanced Web trainings.
My first alarm appeared while searching and learning myself about Service Workers. You will find that most of the samples out there on the Web, are basically, the same code! Meaning that most of the time you will find yourself just pasting the same code on every project.
My second alarm sign appeared a couple of weeks ago during a training in San Francisco. One of my students, after creating our first Service Worker with the basic AppCache code, he asked me: “Ok, now tell me where is the jQuery of Service Workers?”
The jQuery of Service Workers? Of course, he realized that for the typical use-case of a cache for a Web App we need a lot of low-level code that on most situations we don’t need to write every time and we will end using a framework on top of it, or just pasting the same code.
“But we have more power!” you are thinking. Of course, I didn’t say we don’t, I didn’t say we should remove Service Workers support. But, do we need that power for every webapp? If you want to manage all your HTTP requests with the fetch event, that’s great. It’s great to have the ability to do it. But do we need to get there for replacing AppCache on most typical use cases?
Do you remember when FlexBox spec was broken? The solution was to release a new spec, not to release a JS low-level event so we can return coordinates and sizes on every element every time the browser needs to layout. Service Workers are like that.
Other engines #
The last alarm sign I saw was yesterday after I tweeted about this. To be honest, it’s weird to receive a reaction from a Web Engine, but I think it should mean something. The @webkit Twitter account liked 3 of my Tweets:
That also made me thinking that Edge and WebKit not working on SW yet should have reasons. Implementing Service Workers isn’t so simple from a browser’ architecture point of view, such as a new lifecycle and executing background code on some OSs (such as iOS) with its own challenges. Do we really need that sledgehammer to provide a better alternative to Application Cache?
Service Worker has a high priority on Edge but we have no word on Safari that can potentially leave half of the mobile users without support for a modern AppCache alternative
If Chrome and Firefox will remove support for AppCache in the near future, we are again breaking the Web. Half of the Web will support AppCache and Half of the Web Service Workers, at least for supporting offline experiences.
It’s the Cache Storage API, not Service Workers #
Most of the stuff that has to do with caching requests are not really inside the Service Workers idea. It’s about a new API offered through the global caches object (informally known as Cache Storage API) that somehow is still behind the Service Worker spec’s umbrella, even when it’s available on normal scripts served behind TLS (go now, open the browser’s console and type caches).
I think we should definitely separate the Cache Storage API from the Service Worker spec because now we know that with Service Workers we have a new whole universe for Web apps that have nothing to do with caching.
A higher level API #
Application Cache has a simple spec. You just create a manifest file (on a weird format, I get that), you define it in the HTML and that’s all. Optionally you have a couple of events you can bind to and that’s all. Of course it has lots of problems too, but we just need to think about them.
<html manifest=”appcache.manifest”>
Can you emulate AppCache with Service Workers? Again, yes you can! You will probably hardcore the list of your app’s resources inside your SW code, you will call a couple of promise-based functions and you will capture every HTTP request and serve it from the cache if it’s there.
Look at a typical code today to replace Application Cache (from HTML5Rocks)
var CACHE_NAME = 'my-site-cache-v1';
var urlsToCache = [
'/',
'/styles/main.css',
'/script/main.js'
];
self.addEventListener('install', function(event) {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});
You will need to add more code also to detect changes somehow on your resources and update them.
At one point I think the Chrome team realized that the Service Worker API is too low level, so they’ve released two tools to help us with it: sw-toolbox and sw-precache. The problem is: I don’t think we need a “SW jQuery”. We need to use Vanilla AppCache code. I don’t think most web designers and developers want to get into the HTTP layer just to pre-cache some files to provide an offline experience. We should have a one line solution.
I don’t think we need a “Service Worker’s jQuery”. We need to use Vanilla AppCache code.
My open question to the community is: why aren’t we proposing a high level API to provide Web App cache support without the need of low level code? It can be part of the Cache Storage API for example.
I’ve received answers such as “the code is really simple”. Low level doesn’t mean difficult! It can be simple code but it’s low level. Low level means that we are trapping every HTTP requests as a proxy. I don’t think we need that on a lot (most?) situations. I don’t want to rewrite the browser’s network layer on every project.
A new high level API should have:
- A manifest file (in JSON format?) to declare all your resources. Right now, the recommendation is: “do it yourself”. I think we need an standard format.
- A simple way on that manifest file to declare cache policies per resource or per package (Network First, Cache First, etc.)
- A simple way on that manifest to declare timestamps or versions so the browser will know when to update it.
- No need to write a Service Worker (if the implementation wants to use a SW, it’s up to the User Agent.)
- No need to serve the files from the cache myself; it’s a browser’s job!
- Simple events per resource of operation to know the status of the installation/update process.
I know that some of these stuff is available on sw-toolbox and sw-precache, but I don’t want to use a framework for the most typical use-case. I don’t want the need of a node script or a Grunt activity on ever Web project. The Web should be simpler. Then, if you need to customize something, go down into the Service Worker if it’s available. I’m not against that. In fact, I did a couple of interesting things with SW :).
And finally, with a higher level API we might see Apple and other vendors implementing it sooner than later. It’s much easier to implement a better Application Cache API than Service Workers. If Apple doesn’t want background JavaScript execution, we will at least have support for an App Cache that is more secure and more powerful than today’s (obsolete?) API.
What do you think?