Say first PWA

  1. Concept: Progressive Web applications provide an installable, app-like experience on desktop and mobile devices
  2. Implementation conditions
    • Use responsive design because it will be available on a desktop or mobile device
    • Fast, use service worker**** to pre-cache application resources (HTML/CSS/JS/images) needed for runtime
    • Installable, using the Web Application Manifest and beforeInstallPrompt events to inform and notify the user that it is installable

Besides, the service worker

The service principle of worker

A service worker is a script that the browser runs in the background independently of the web page, opening the door to functionality that does not require web pages or user interaction. They now offer features including push notifications and background syncing. In the future, additional features such as periodic synchronization or geo-fencing will be supported. We study intercepting and processing network requests, including managing responses in the cache through it. Because of the above features, it enables web apps to support offline experiences. Service worker:

Service Worker life cycle

To install a service worker for your website, you need to register the service worker in the js section of your page. Registering the service worker causes the browser to start the service worker installation step in the background.

During the installation process, we usually need to cache some static files. If static files have been cached successfully, the service worker is installed and waiting to be activated. Otherwise, the installation fails and the service worker will not be activated (if this happens, it will retry next time).

When activated, the Service Worker exerts control over all pages in its scope, but the pages that registered the Service Worker for the first time need to be loaded again before they become under its control. After the service worker imposes control, it will be in one of two states: the service worker thread terminates to save memory, or the fetch and message event is processed, which will occur after a network request (FETCH) or a postMessage is issued from the page.









Service worker application

1. Register a service worker

Using the API:

  • ServiceWorkerContainer (navigator. ServiceWorker) The serviceWorkerContainer interface provides container-like functionality for the service worker. This includes registering, uninstalling, updating and accessing the status of service workers, as well as their registrants
  • ServiceWorkerContainer. Register (scriptURL, the scope, the base]), and returns a promise object, the value is ServiceWorkerRegistration. The register() method of the ServiceWorkerContainer interface creates or updates a ServiceWorkerRegistration for the given scriptURL.
if ('serviceWorker' in navigator) {
  window.addEventListener('load'.function() {
    navigator.serviceWorker.register('/sw.js').then(function(registration) {
      // Registration was successful
      console.log('ServiceWorker registration successful with scope: ', registration.scope);
    }, function(err) {
      // registration failed :(
      console.log('ServiceWorker registration failed: ', err);
    });
  });
}
Copy the code

2. Listen to its own install event to add files to cache

Using the API:

  • Event.waituntil, as an API for extendableEvent, which is part of the service worker lifecycle and extends the life of install and Activate events globally, Make sure no function events are scheduled until obsolete Caches are removed.
  • Caches. Open (CACHE_NAME), which represents the storage of the Cache object and is globally accessible. The caches. Open method gets the Cache instance, which is also returned as a promise.
  • Cache. addAll(urlsToCache), cache provides a storage mechanism for cached Request/Response objects. AddAll grabs an array of urls, retrieves and adds the returned Response object to the given cache object.

Above, when the Install event occurs, the service worker starts grabbing the files that need to be cached and adding them to the corresponding cache object. The install event ends when the cache ends.

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');
        returncache.addAll(urlsToCache); })); });Copy the code

3. Listen for the FETCH event to return the request content from the cache

Situation: The service worker will start receiving fetch events when the user moves to another page or refreshes the current page (the user uses the FETCH to request static resources while refreshing or moving to another page)

Using the API:

  • Event.respondwith, the FETCH event API, blocks the browser’s default FETCH handler and allows the user to provide a promise as a response to the FETCH event.
  • Caches. Match, which checks if a given Request is the key of any Cache object tracked by CacheStorage and returns a resolve promise that matches.
  • Caches. Open: Use the caches. Open method to obtain the Cache instance of the cacheName.
  • Cache.put, which simultaneously grabs a request and its response and adds it to a given cache.

Details: After the service worker listens to the FETCH event, it checks if the current request is the key of any Cache object tracked by the CacheStorage object. If so, it returns a response for the matching request. If no response is found, it fetches the current request again. And after the fetch arrives, its response is added to the cache instance.

self.addEventListener('fetch'.function(event) {
    event.respondWith(
        caches.match(event.request)
        .then(function(response) {
            if (response) {
                return response;
            }
            var requestToCache = event.request.clone();
            return fetch(requestToCache).then(function(response) {
                if(! response || response.status ! = =200) {
                    return response;
                }
                var responseToCache = response.clone();
                caches.open(cacheName).then(function(cache) {
                    cache.put(requestToCache, responseToCache);
                });
                returnresponse; }})})))Copy the code

4. Update service worker

Situation: At some point, your Service Worker needs to be updated. In this case, you need to follow the following steps:

  1. Update your service worker JavaScript file. When the user navigates to your site, the browser tries to re-download the script file that defines the Service Worker in the background. If the Service Worker file differs in bytes from the file it is currently using, it is treated as _ new Service_ Worker.
  2. The new Service Worker will start and the install event will be triggered.
  3. At this point, the old Service Worker still controls the current page, so the new Service Worker will enter the waiting state.
  4. When the currently open page on the site closes, the old Service Worker is terminated and the new Service Worker takes control.
  5. It will be triggered when the new Service Worker gains controlactivateEvents.

The reason we want to do this in the Activate callback is that if any old caches are cleared during the setup step, any old Service Worker that continues to control all current pages will suddenly be unable to serve files from the cache.

Using the API:

  • Event.waituntil, as an API for extendableEvent, which is part of the service worker lifecycle and extends the life of install and Activate events globally, Make sure no function events are scheduled until obsolete Caches are removed.
  • Caches. Keys, which iterates through the list of all Cache objects
  • Caches. Delete, looks for a Cache object that matches cacheName, and if it does, deletes the Cache object and returns a Promise that resolves to true. If the Cache object is not found, false is returned.

When a service worker is activated, all current Cache objects are checked. If they are not in the service worker’s Cache list, they are considered old and removed from the cacheStorage.

self.addEventListener('activate'.function(event) {

  var cacheAllowlist = ['pages-cache-v1'.'blog-posts-cache-v1'];

  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheAllowlist.indexOf(cacheName) === -1) {
            returncaches.delete(cacheName); }})); })); });Copy the code

Hands-on practice

1. Import and register in the startup file

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta Name = "viewport" content = "width = device - width, initial - scale = 1.0" > <! <link rel="manifest" href="./manifest.json"> <! <link rel="stylesheet" type="text/ CSS "href="/cache1.css"> <title>pwa</title> </head> <body> <div id="app" class="test">test1</div> <! <script SRC ='/cache1.js'></script> <script> if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/sw.js').then((registration) => { console.log('Service worker registration', registration); }, (err) => { console.log(err); }) }) } </script> </body> </html>Copy the code

2. The service worker file looks like this

const cacheName = 'my-cache';
const cacheList = ['cache1.css'.'cache1.js'];

self.addEventListener('install'.function(event) {
    console.log('installing', caches, event);
    event.waitUntil(
        caches.open(cacheName).then(function(cache) {
            console.log('opening', cache);
            // Fetch the url array, retrieve and add the final returned response object to the cache
            return cache.addAll(cacheList);
        })
    )
})

self.addEventListener('fetch'.function(event) {
    console.log('fetch', caches.keys());
    event.respondWith(
        caches.match(event.request)
        .then(function(response) {
            if (response) {
                return response;
            }
            var requestToCache = event.request.clone();
            return fetch(requestToCache).then(function(response) {
                if(! response || response.status ! = =200) {
                    return response;
                }
                var responseToCache = response.clone();
                caches.open(cacheName).then(function(cache) {
                    cache.put(requestToCache, responseToCache);
                });
                returnresponse; }})})))Copy the code

3. The net effect is…





Yeah, he’s activated. Just manually refresh it



You can also check offline

4. Time comparison


When I do not use the service worker





When I have a service worker



More and more

1. Vue-cli 3 pWA used by the Google teamworbox webpack plugin

2. Service worker also has the function of pushing messages


Refer to the article: your first pwa application: developers.google.com/web/fundame… Service worker basis using: googlechrome. Making. IO/samples/ser… Web worker use: www.html5rocks.com/en/tutorial… Service worker push message: juejin.cn/post/684490… @ vue/cli – plugin – pwa: github.com/vuejs/vue-d…