What is PWA

PWA is short for Progressive Web Applications. If you want to learn more about the basics of PWA, go check the Google PWA official website.

Also, I did a brief intro to PWA in the CORP as tech share a while before. The content mainly comes from the PWA official site and the offline cookbook. Check it out if you desire.

Apply PWA Features to The Blog

I want to apply these beautiful PWA features to the blog, so that I can add the app to my home screen and browse the blogs offline. Now, let’s go through how to do that step-by-step.

First of all, Generate the Service Worker JavaScript

  • I need to generate the Service Worker JavaScript, sw.js, with all my content and pre-cache the pages into the cache. This way, when service worker is installed, everything has been pre-cached. It will enable the full off-line mode by all the pre-cached files. This is the so-called install step of PWA life-circle.

    const cacheName = 'sr-precache-##REVISION##';
    const PrecacheList = ##PRECACHE_LIST##;
    self.addEventListener('install', function(e) {
      console.log('[SW] Install');
        caches.open(cacheName).then(function(cache) {
          console.log('[SW] Caching all files.');
          console.log('[SW] SkipWaiting');
          return self.skipWaiting();

    There will be a post-build script to replace ##PRECACHE_LIST## with the files in my public folder after I generated my site. The script will also replace ##REVISION## with the git sha of origin/master.

    Also, as you can see, there is a command self.skipWaiting() to tell SW to skip waiting, meaning the service worker activates as soon as it’s finished installing, even for updating.

  • Then, I would want SW to use these pre-cached files for the requests. So I added lines to customize the fetch event in sw.js.

    self.addEventListener('fetch', function(e) {
        caches.match(e.request).then(function(response) {
          return response || fetch(e.request);

    This is a very basic cache strategy, serving from cache and then network, a.k.a, cache-first.

  • After the steps above, the web app now works when offline. However, there are still issues.

    • The cache will be invalid after I update the site, I need to remove the invalid cache.
    • SW will wait for all the tabs to close so that the new sw.js could apply to the tabs.

    So, I need to update the activate step so that I can fix these issues.

    self.addEventListener('activate', function(e) {
      console.log('[SW] Activate');
        caches.keys().then(function(keyList) {
          return Promise.all(keyList.map(function(key) {
            if (key !== cacheName) {
              console.log('[SW] Removing old cache', key);
              return caches.delete(key);
      return self.clients.claim();

    Since every update will change the git sha, I will get a unique new sha whenever there is an update. Then I just need to delete caches which is not the latest one.

    Also, with self.clients.claim(), I can take control of uncontrolled clients/tabs within my service worker once it’s activated.

With all these steps above, the basic sw.js is initialized.

Let’s Register The Service Worker JavaScript

It’s easy to do this. Just test the browser to see if it supports SW, and register if so.

if ('serviceWorker' in navigator) {
    console.log('Service Worker Registered');

Create The Web App Manifest

The web app manifest is a simple JSON file that tells the browser about your web application and how it should behave when ‘installed’ on the user’s mobile device or desktop. Having a manifest is required by Chrome to show the Add to Home Screen prompt.

  • Add name & short_name
    • The name is used in the Add to Home Screen prompt, while the short_name is used as the app name after being added to home screen.
  • Add Icons
    • Ah.. I just used the Preview app on Mac to create my PNG icons.
  • Add start_url & scope
    • The start_url is the url when the app is launched as a fresh start after being added to home screen.
  • Add backgrou_color & theme_color
    • These two will affect the Android Chrome header color and the app splash screen after being added to home screen.
  • Add display
    • If you want the immersive experience, try standalone(with only status bar) or even fullscreen(no status bar).

Now, let’s register this configuration file in the <head> tag of all the pages.

<link rel="manifest" href="/manifest.json">

It is NOT Enough, Yet

  • For iOS

    As we all know, PWA is not an Android only feature, it also works on iOS with iOS 11.3. However, you can barely find it on iOS 11.3 release notes, even Google says PWA is firstly introduced by Steve Jobs. And in this medium post, there are a huge ton of useful information about PWA on iOS.

    Why Google and Apple always do the same thing in a different way? And why Google is doing the standard way and Apple is doing the non-standard way? (Or, at least Google is making his way the standard way. This is the reason why we need to be open, instead of locking ourselves into a cage which looks big, but will become smaller and smaller.)

  • Client Tracking

    With Google Analytics, I can track my blog visits very easily. Google has done really nice shits. (PWA is one of the shits!)

  • Local Dev

    Actually, when you initialized the PWA, you don’t need it for dev mode when writing posts or updating blog styles. The cache will breake some functions of the auto-reload logic.


So, here it comes, the PWA for the blog.

The Blog PWA

PWA is going to change rules of the game, hopefully, if and only if it will be more and more improved and applied. And it did really pushing the web to the next milestone.


This is not a post to praise Google. Actually, Apple is also doing great. A lot of people love iPhones. BTW, I love Mac. Even Microsoft is trying its best to serve bests apps on iOS/Android, when WinPhone has been dying.

I mean, every company has its good side, and bad side as well. Maybe they are saying “don’t be evil”, while they are doing the evilest things.