PWA (Progressive Web Apps, Progressive Web Applications)

concept

PWA is a new concept of modern Web development. It does not rely on a specific API, but uses a variety of technologies and patterns to develop Web applications, and has the characteristics of both Web applications and native applications, so as to achieve the goal of the best Web experience.

An application can be called A PWA and should have the following characteristics:

Discoverable content can be discovered by search engines.

Installable can appear on the device’s home screen.

Linkable allows you to simply share it with a URL.

Network Independent can run offline or with poor Internet speeds.

Progressive is still available on older browsers and fully functional on newer browsers.

Re-engageable It can send notifications whenever there is new content.

Responsive It works on any device with a screen and browser — including cell phones, tablets, laptops, TVS, refrigerators, etc.

Safe makes the connection between you and the app secure and prevents third parties from accessing your sensitive data.

Therefore, determining whether a Web application is PWA depends on whether it has the same features as a native application, such as desktop ICONS, offline caching, and notification push. Of course, his benefits are also a lot of, such as: fast! Really fast and accessible offline; Users can agree to add ICONS to the home screen for next visit; It can also achieve system-level message push; In short, getting closer to the native app experience!

The technical implementation

The core technologies required to implement a PWA include: Service Worker + manifest. json + HTTPS

Service Worker

Service Worker is an event-driven Worker registered under a specified resource and path. Therefore, like other types of workers, it cannot access DOM. It is not allowed to use synchronous APIS, such as localStorage, but it can intercept and modify the accessed resource requests. Resources are cached and updated by a variety of caching strategies.

  • Sign up for aworker:
if ('serviceWorker' in navigator) {
  navigator
  .serviceWorker
  .register('/sw-test/sw.js', { 
    scope: '/sw-test/' 
  })
  .then(function(reg) {
    // registration worked
    console.log('Registration succeeded. Scope is ' + reg.scope);
  }).catch(function(error) {
    // registration failed
    console.log('Registration failed with ' + error);
  });
}
Copy the code
  • Installation and activation: Populate the cache

After the SW is registered, the browser will try to install and activate it, and the install event will be triggered when it is installed. To achieve offline caching, you need to use a new storage APi-Caches, which is a global object on the SW that can store resources requested by the network. Unlike standard browser storage, it is a persistent cache specific to your domain;

this.addEventListener('install'.function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/sw-test/app.js']); })); });Copy the code
  • Controls the response to requests

Any request controlled by SW will trigger the FETCH event, and the specific response content of the request can be controlled by monitoring the event.

As above, after the installation is successful, you can cache a batch of specified resources, so now you can intercept the request, and then match the cache results as a response, or request a new version of the resource, or even respond to the specified content, you intercept, then you have the final say!

// Respond to cached requests

this.addEventListener('fetch'.function(event) {
  event.respondWith(
    caches.match(event.request)
  );
});

// Respond to custom content

const res = new Response('

Hello, service worker!

'
, { headers: { 'Content-Type': 'text/html'}}); event.respondWith(res);// Cache fetch failed to rerequest the latest event.respondWith( caches.match(event.request).then(function(response) { returnresponse || fetch(event.request); }));Copy the code
  • updateService Worker

If a new version of SW is installed after the page is refreshed, the new version will be installed in the background and will not take effect immediately after installation. When no page is using the old version of SW, the new version will be activated and respond to requests.

// Update to version V2

this.addEventListener('install'.function(event) {
  event.waitUntil(
    caches.open('v2').then(function(cache) {
      return cache.addAll([
        '/sw-test/app.js']); })); });Copy the code
  • Delete old cache

When a new version is available and the old version is still running, the old cache needs to be cleared to prevent too much cached data from occupying disk space. Clean up the old cache by listening on the activate event.

self.addEventListener('activate'.function(event) {
  var cacheWhitelist = ['v2'];

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

Manifest.json

This file lists all configuration information for adding applications to the desktop. If you modify this file, the application style that has been added to the desktop will not change. You need to add the application to the desktop again:

<link rel="manifest" href="/manifest.json" />
Copy the code

Such as:

{
  "name": "name"."short_name": "short_name"."description": "description"."icons": [{"src": "logo.png"."sizes": "192x192"."type": "image/png"
    },
    {
      "src": "logo.png"."sizes": "512x512"."type": "image/png"}]."share_target": {
      "action": "compose"."params": {
        "title": "title"."text": "text"."url": "url"}},"start_url": "/index"."scope": "/"."display": "standalone"."orientation": "portrait"."background_color": "#F3F3F3"."theme_color": "#F3F3F3"."related_applications": []."prefer_related_applications": false
}
Copy the code

HTTPS

HTTPS encrypts data on the basis of HTTP, involving asymmetric encryption and symmetric encryption. Even if data is hijacked during transmission, hackers can do nothing as long as the private key is not leaked. Therefore, data security is very high

Letsencrypt is a free HTTPS certificate provider for web sites around the world, and supports a wide domain name, very recommended use, large companies rich please ignore;

Certbot is an official tool provided by LETsEncrypt for obtaining and updating HTTPS certificates. Certbot.eff.org/ on its website, you can choose how to use it according to your system and services. CentOS 7 and Nginx 1.16.0 as an example, see how to make HTTPS free on the web.

  • To obtaincertbotThe client
wget https://dl.eff.org/certbot-auto
chmod a+x ./certbot-auto
./certbot-auto --help
Copy the code
  • configurationnginx

This step is used to verify that the domain name is accessible. The tool then creates a temporary file in the directory corresponding to the configured root. If the file cannot be accessed, the user has no right to obtain the certificate of the domain name.

location ^~ /.well-known/acme-challenge/ {
   default_type "text/plain";
   root     /path/to/www;
}
 
location = /.well-known/acme-challenge/ {
   return 404;
}
Copy the code

Don’t forget to restart nginx:

sudo nginx -s reload
Copy the code
  • Generate a certificate
./certbot-auto certonly --webroot -w /path/to/www -d  famanoder.com -d www.famanoder.com 
Copy the code

-d *. Famanoder.com -w is the root of nginx, -d is the domain name that needs to obtain a certificate, -d can be used multiple times, or can directly generate the certificate of the pan-domain name, -d *. Famanoder.com, which is a good example of how many cloud services are not only expensive, but also does not support the pan-domain name. Here, big companies rich please ignore!

  • Automatic Certificate Update

After a certificate is generated, you can choose whether to renew the certificate automatically because the validity period of each certificate is three months.

./certbot-auto renew --dry-run
Copy the code

Using this command, you can test whether the automatic renewal of the previous step is available.

You can also manually update the certificate:

./certbot-auto renew -v
Copy the code

Or set up automatic updates with the command:

./certbot-auto renew --quiet --no-self-upgrade
Copy the code
  • Use certificate
listen 443 ssl;
server_name .famanoder.com;
index index.html;
root  /path/to/www;
 
ssl_certificate      /etc/letsencrypt/live/famanoder.org/fullchain.pem;
ssl_certificate_key  /etc/letsencrypt/live/famanoder.org/privkey.pem;
Copy the code

Read more about how to configure HTTPS on Nginx.

Actual combat PWA

The above basic introduction of PWA and the infrastructure required by a PWA application are described. Next, offline-Plugin is used to practice PWA in the project.

First, introduce it into the entry file of our application to ensure that the current page can communicate with the service worker.

import(/* webpackChunkName: "offline" */'offline-plugin/runtime')
.then(offline= > {
  offline.install({
    onUpdating: (a)= > {
      console.log('SW Event:'.'onUpdating');
    },
    onUpdateReady: (a)= > {
      console.log('SW Event:'.'onUpdateReady');
      offline.applyUpdate();
    },
    onUpdated: (a)= > {
      console.log('SW Event:'.'onUpdated');
      // window.location.reload();
      // alert(' New version available, want to refresh? ');
    },
    onUpdateFailed: (a)= > {
      console.log('SW Event:'.'onUpdateFailed'); }}); });Copy the code

The plugin will package the generated files from Webpack, generate sw.js files, and configure webpack:

// webpack.config.js

const OfflinePlugin = require('offline-plugin');

module.exports = {
  / /... .
  plugins: [
    / /... .
    new OfflinePlugin({
      ServiceWorker: {
          events: true}}})]Copy the code

This way, our application can support PWA, which can be viewed at the console;

Use pwa and very important, is how to update, as mentioned above, sw after installing the new version will not immediately active, most of the time requires the user to refresh the page again will only take effect, of course, this is also associated with specific caching policy, at present, watch some pwa site, will find that when there are new update, The plugin runtime provides an onUpdated hook, which notifies the page when the latest version is installed. Here we can call the modal box component to remind the user whether to refresh the page to use the latest version.