Service workers and Progressive Web Application (PWA) are very hot topics right now. And as far as on my latest project I’ve integrated the service worker and PWA I want to share my experience from the perspective of real production usage, benefits and drawbacks. I hope that this information helps.
Currently on my project I’ve faced a need to implement additional client side caching in the Angular application. This decision was influenced by several important conditions in which our application exists. So let me try to give a bit of context here.
The main problem is that I have a couple of third-party services which I can’t control but these services provide very important parts of data. Actually to render most parts of our UI I retrieve data from Microsoft Graph API which for us works very unstable. My observation is that from 1 to 15 percent of the requests fail with “Gateway Timeout” response.
The second important condition is that our application has a very limited audience of users and most of them are using our application quite often, several times a day.
The third and the last important condition is that data in several critical parts of application refreshes not very often, several times a week in most of the cases.
Taking into account all these details I’ve assumed that client side caching can significantly improve user experience of our audience. The first implementation I’ve delivered was based on
localStorage caching. This approach didn’t work well for us because of two main reasons:
localStorage is limited in size (5-10 MB depending on browser) and the fact that it requires a lot of manual work (at least a naive implementation requires code for each web service).
So as the second try I’ve decided to give a try with service workers. Unfortunately after implementation I’ve faced several important issues and in case I will not be able to overcome those issues I will remove service worker and PWA support from the application. At least for now.
Disclaimer! It’s important to note that this information is based on experience of integration of Angular’s service worker implementation (more info in the official documentation). Some of the issues that I’ve faced are related to this particular implementation and probably can be improved. Some of them are not. Also I’ll not distinguish PWA as a separate topic because when you finished with service worker you’ll get PWA almost for free (if you need of course).
ease of use
I don’t have much to say here. If we are talking about Angular’s Service Worker and PWA – it’s basically part of framework (yet optional).
So to integrate service worker to you application and then to transform your web application to progressive web application you need to write a couple of configuration files. Piece of cake.
Here I’ve faced the first difficulties:
To deactivate the service worker, remove or rename theangular.io
ngsw.jsonfile. When the service worker’s request for
404, then the service worker removes all of its caches and de-registers itself, essentially self-destructing.
This quote contains an interesting limitation. Let’s imagine that your project is not a huge enterprise product which is available 24/7 and sometimes (for example once a month on the weekend) has a planned maintenance work for a couple of hours (installation of OS updates, backup creation, etc.). It’s quite a standard situation for B2B solutions which are rarely used during weekends. Yet still a lot of users are not shutting down their workstations during the weekend and do not close browsers. As a result after such a maintenance day all caches will be destroyed and users will suffer from new application bootstrapping on Monday.
But it’s not all unfortunately. If we are talking about B2B enterprise applications it also means that these applications are secured by authentication. For example in my case authentication is provided by Single Sign-On mechanism. So any time user’s session expires user redirected to completely different application to update authentication information. And of course, so does the service worker. It receives the HTML instead of JSON configuration, think that something bad happened and destroys itself with all the caches. And as you can imagine this can happen much more often than server maintenance.
As a result we have a serious set of limitations for proper integration of service worker:
- Service worker configuration file should be available 24/7 to not self-destruct occasionally;
- It’s recommended to not protect configuration file by any authentication. Which nowadays is quite complicated in my opinion, because most of the companies worldwide are very careful in questions of security (not without a reason of course);
Personally I find existing caching strategies are not flexible enough. This probably can be resolved by copy-pasting service worker into your solution and implementing suitable caching strategy. But it returns us to “ease of use” and of course such plan significantly increases the time required for adoption. Caching strategy is not something very simple and quick to implement. I strongly recommend to proper test caching mechanism before releasing to production and it will be nice to cover them with integration/e2e tests.
So let me provide you 2 scenarios where existing strategies are not flexible enough from my perspective.
I need a way to cache some data for X minutes and always return this data from cache during this period of time. When cache is deprecated I want service worker to request new data but return the cached data for the very last time for better performance. Now let’s take a look at what Angular’s implementation is providing to us:
- performance. At the very first glance looks like a strategy I need. However as usual it’s not so simple. The problem with this strategy is that when cache is marked as deprecated service worker will not return it to the user, it will wait for fresh data. For some services it’s fine, but for slow services it can be a problem. And as I’ve mentioned in the beginning of the article services which I consume in my application are very slow in some cases and for me providing a stable performance to my audience is crucial;
- freshness. I can simulate the required strategy by setting the timeout to zero seconds. And from the user’s perspective it will work as intended. But from the developer’s stand point the issue here is that we are making a lot of redundant calls during the time when we are sure that data is still fresh.
The second interesting caching strategy which I’m really looking for is “manual cache invalidation”. This can be very useful in some cases. Let’s imagine a user profile. It’s not the data you want to request too often because it’s not updated for months in 99% of the cases. And for me “performance” strategy is working perfectly here. However there is an interesting scenario when user manually updates his/her profile. And in this case I want to deprecate cache for particular service manually. Moreover, if we are talking about REST API we can use an assumption that endpoint’s cache should be deprecated in case the endpoint was called using
DELETE verbs. But again it’s not part of the existing solution.
Frankly speaking PWA was not part of my requirements, however due to the fact that enabling PWA after setting up the service worker costs almost nothing I’ve spent some time to prepare a manifest file for my application. I’ve spent some addition time to test this version of my application on Android and iPhone and was a bit disappointed with the results.
The first important thing (probably I did something wrong) I wasn’t able to update the name of the application nor icons after redeploying the application. I’m not sure why it happens and if there any way to perform this. The scenario for this feature is quite simple, sometimes your application need a redesign and of course you want to update the icon of the application. But it didn’t work in my case. Needs additional investigation though.
The second and more important problem is that the iPhone’s browser and PWA installed on the smartphone do not share cookies, storage and caches. As a result migration from web application to PWA on iPhone results in the additional authentication request for all users, which is quite annoying.
And the last one, blocker. By default iPhone prohibits PWA to change domain making authentication using Single Sign-On mechanism with the redirect to third-party domain completely impossible. The screen turns blank and users cannot do anything with that. For most of the enterprise applications I’ve developed so far it’s a complete showstopper, which makes PWA useless.
I’m not trying to say that Service Worker or PWA are completely useless, of course no. But I wanted to highlight some limitations in adoption which I’ve faced during proof of concept implementation. It’s important to take these limitations into account before investing time into development of features which are provided by these technologies.
They can save a lot of time and money for development of native application or custom client-side caching . And they will work perfectly if you don’t have limitations which I’ve described in this article.
Thanks a lot for reading! I hope you’ve enjoyed. If you find this material useful, don’t forget to subscribe and share with your colleagues and friends! Thanks!