This article mainly shares PWA’s practical experience in road travel:

  • Introduction of PWA
  • Local HTTPS Debugging
  • PWA configuration
  • Online deployment
  • PWA update
  • PWA degradation processing

Main technology stack:

  • vue
  • PWA
  • webpack
  • nginx

This solution is more suitable for projects that are already SPA architecture and want to upgrade PWA (service-worker.js for sw).

Introduction of PWA

Offline application

  • General front-end loading optimization template and resource caching in users’ nearest CDN (compared with e-commerce logistics pre-warehouse)
  • Direct local caching of resources including templates after the introduction of PWA (compared to vending machines at home)

You can go to outweb. IO/to feel the PWA application, you will see many famous sites in China have also upgraded PWA

PWA debugging

Configuring the HTTPS local environment facilitates PWA project debugging. For details about how to generate the local certificate, see mkcert. Nginx configuration:

        listen       443 ssl;
        server_name  localhost2;
        ssl_certificate      /Users/liuze/localhost2.pem;
        ssl_certificate_key  /Users/liuze/localhost2-key.pem;
Copy the code

Nginx mainly does static resource output. For more information about server configuration, please refer to vue server configuration:

        location @ipad-index {
            add_header Cache-Control no-cache;
            expires 0;
            root /Users/liuze/workspace/klook-fe/klook-gds-hotel-ipad/dist/;
            try_files /index.html =404;
        }

        location /ipad {
            alias /Users/liuze/workspace/klook-fe/klook-gds-hotel-ipad/dist/;
            autoindex on;
            try_files $uri @ipad-index;
        }
        
         location /pwa-check { Check if the PWA is degradedProxy_pass http://127.0.0.1:3008; proxy_pass_request_headers on; proxy_set_header Host$host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
Copy the code

(Add the 127.0.0.1 localhost2 mapping to hosts.)

PWA configuration

The configuration is mainly based on workbox-webpack-plugin 3.6.3/workbox-sw.js. The reasons are as follows:

  • Relatively native, greatly simplified configuration
  • Downloads have skyrocketed since 2018, NPM Trends
  • Support offline GA

The main configurations are as follows:

        workboxOptions: {
            importScripts:['./sw-prefile.js'],// Insert runtimeCaching: [{urlPattern: /v1/, handler:"networkFirst",
                options: {
                    cacheName: "klook-gds-hotel-ipad-static",
                    expiration: {
                        maxEntries: 50,
                        purgeOnQuotaError: true,
                        maxAgeSeconds: 60 * 60 * 24,
                    },
                    cacheableResponse: {
                        statuses: [0, 200]
                    }
                }
            }],
            clientsClaim: true, // The new service-worker sets itself as Controller and Triggers A"controllerchange" event
            offlineGoogleAnalytics: true,
            navigateFallback: '/ipad/index.html',
            directoryIndex: '/ipad/index.html'
        }
Copy the code

Workbox-webpack-plugin provides two main modes:

  1. GenerateSW generates SW files based on the configuration. Applicable scenarios:

    • Sw only involves simple configuration
    • There is no Web Push involved
  2. InjectManifest mode through the existing SW file reprocessing, applicable scenarios;

    • Involved in Web Push
    • More complex custom configurations

The GenerateSW pattern used here;

Online deployment

Online deployment is similar to local debug configuration in that certificate replacement is required in addition to adjusting nginx pointing to the build directory of the deployment project’s static resources

PWA update

PWA control page, update improper is easy to lead to major page errors; User active update mode is selected here.

  1. Monitor sw update status
  2. Send custom events when the sw is automatically triggered if there is an update
  3. The custom event is triggered to display the update button
  4. The user clicks the update button to trigger the update

Practice:

registerServiceWorker.js

//add interval check after registered
 registered(registration) {
      console.log('Service worker has been registered.')
      updateInterval = setInterval((a)= > {
        registration.update();//dynamically pull service-worker
        console.log('checking update! ')},1000 * 10) // e.g 10s senconds checks
    }
    
//trigger custom event and export resgitration instance
    updated(registration) { //triggered whens service-worker.js changed
          console.log('New content is available; please refresh.')
          document.dispatchEvent(
            new CustomEvent('swUpdated', {
          detail: registration
        })
      );
    }
Copy the code

App.vue

    //add custom event
    document.addEventListener(
      'swUpdated'.this.showRefreshUI, { once: true});//show refresh button
    showRefreshUI(e) {
      this.registration = e.detail;
      this.updateExists = true;
    },
    //click to refresh and post web worker message
    refreshApp() {
      this.updateExists = false;
      if (!this.registration || !this.registration.waiting) { return; }
      this.registration.waiting.postMessage({
        type: 'SKIP_WAITING'
      });
    },
Copy the code

RefreshApp is mainly used for message interaction through Web workers.

If a message is sent, there must be a receiver. Remember that there was a configuration item earlier:

importScripts:['./sw-prefile.js']
Copy the code

sw-prefile.js

self.addEventListener('message', (event) => {
     if (event.data && event.data.type === 'SKIP_WAITING') { self.skipWaiting(); }});Copy the code

The message event listener is injected into the SW, so that the new SW skips the waiting phase when receiving messages, and then combines configuration items

clientsClaim:true
Copy the code

The old and new SW are replaced.

It seems that everyone is happy now that the page has been taken over by the new SW, but the previous requests come through the old SW, so there are two versions of requests on the same page, so it needs to be processed further

    navigator.serviceWorker && navigator.serviceWorker.addEventListener( //triggered by registration.claim
      'controllerchange', () = > {if (this.refreshing) return;
        this.refreshing = true;
        console.log('controllerchange triggered, -> auto refresh!! ')
        window.location.reload(); });Copy the code

Listen for the new SW takeover, and then actively trigger a page refresh, which will be a completely new SW takeover page

PWA degradation processing

Demotion is now handled mainly by sending messages at regular intervals:

  1. Regularly check ‘/ pwa – check’
  2. Determines whether to cancel the PWA based on the return
  3. Clear the periodic check update task at the same time as logging out

Node provides the/pWA-check interface

Summary:

Todos:

  • Pwa conversion amp
  • Front-end monitoring information is sent offline
  • Add to Desktop Statistics
  • .

Welcome correction!

The appendix

As for our passenger road travel, we are opening the positions of front-end and back-end development. We work here at 1075 and do not punch the clock

References:

  • Your first Progressive Web App
  • Give Users Control Over App Updates in Vue CLI 3 PWAs
  • workbox-webpack-plugin
  • Service Worker life cycle
  • PWA’s practical experience in Ele. me