PWA simple introduction tutorial

What is the PWA

MDN official website has a very clear definition of PWA

Progressive Web Apps (PWAs) take traditional Web sites/applications -- with all of the advantages the web brings -- and add a number of features that give them many of the user experience advantages of native apps.Copy the code

Simply translated: PWA is like a traditional Web app, but it’s better.

PWA is a Google technology that you can find out more about here. Or go to MDN to view the document.

PWA preparation knowledge

PWA is new, not just a new API, but more importantly, it introduces a whole new set of standards and syntax as a foundation. Before you can learn PWA, you need to make sure that you are familiar with the following:

  1. ES6 standard syntax
  2. Promise. This is the most important thing to know, and if you’re not familiar with it or haven’t heard of it, you might want to think about it
  3. Fetch, a new API for fetching resources, including Request, Response, Header, and Stream
  4. WebWorker, JavaScript solution to single thread solution
  5. Cache API

PWA’s pitfalls

When PWA is deployed online, make sure it is under HTTPS, not HTTP. Of course, for ease of development, browsers support deployment on localhost.

After PWA finishes caching, many times you will find that the code does not change or does not automatically update the worker as expected, so try clearing the cache.

PWA is not supported by all browsers; in fact, few browsers support PWA by default. Chrome and FireFox do this better, so this article uses Chrome as a development tool.

Some preparation

First, let’s start with some simple preparations. PWA needs a server, and we use Koa to simply set up a server. First, create the development directory and initialize some files:

Mkdir pwa-test CD pwa-test touch index.html touch index.js touch sw.js // server script touch server.js // initialize nodejs project directory, All the way to NPM initCopy the code

Then install some packages for development use

npm install koa koa-static --save-dev
/ / or
yarn add koa koa-static --dev
Copy the code

Next, we write the following simple code in server.js:

const Koa = require('koa');
const Static = require('koa-static');
const path = require('path');  

const app = new Koa();
const staticPath = '/';

app.use(Static(path.resolve(__dirname, staticPath)));

app.listen(8080);
Copy the code

Then write something simple in index. HTML


      
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>PWA TEST</title>
</head>
<body>
    <script src="./index.js"></script>
</body>
</html>
Copy the code

Start the PWA tour

service worker

The most important part of PWA is the service worker. It is similar to but different from traditional workers. Operating a Service Worker is as simple as registering it. Let’s introduce the specific use.

First, check whether the service worker is supported:

// index.js
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js').then(reg= > {
        console.log('service worker registed! ');
    }).reject(err= > {
        console.log('Opooos, something wrong happend! '); })}window.onload = function() {
    document.body.append('PWA! ')}Copy the code

This code uses promises, and when you register a file, it returns a Promise. Note that the file received by Register is not a path relative to the path of the current file, but rather a path relative to the root path. In other words, if your pwa applications running on https://www.example.com/pwa, then you register sw. Js is not. / sw. Js, and should be/pwa/sw. Js.

We have now registered a service Worker, but it doesn’t have any content yet. Next we write the following code in sw.js:

// sw.js
self.addEventListener('install'.function (e) {
    e.waitUntil(
        caches.open('v1').then(cache= > {
            return cache.addAll([
                '/index.js'.'/index.html'.'/']); })); }); self.addEventListener('fetch'.function (event) {
    event.respondWith(
        caches.match(event.request)
        .then(function (response) {
            // Check to see if it has been cached
            if (response) {
                return response;
            }

            var fetchRequest = event.request.clone();

            return fetch(fetchRequest).then(
                function (response) {
                    // Check whether the request is valid
                    if(! response || response.status ! = =200|| response.type ! = ='basic') {
                        return response;
                    }

                    var responseToCache = response.clone();

                    caches.open('v1')
                        .then(function (cache) {
                            cache.put(event.request, responseToCache);
                        });

                    returnresponse; }); })); });Copy the code

Self is the equivalent of Global in Worker, where we register two events: Install and fetch. These two events are called when the service Worker installs and downloads files respectively.

The first is install. When you register a file, install is called, which means that the file will be installed into the service Worker. The install event has a waitUntil function that accepts a Promise as an argument. It ensures that the installation is completed after the incoming Promise has been executed.

In waitUntil, we use caches. This is a global variable, we use open to open a cache, we assume the cache library is called v1, if not, it will be created automatically.

Caches. Open (‘v1’) also returns a Promise, and its callback receives a cache, the corresponding cache library. Next, we added the files /index.js and /index.html using addAll. Remember that operations on the cache should return, otherwise waitUntil will not receive instructions on when to complete the installation.

What is the other event fetch for? It intercepts the fetch request for the web page. In this way, we can intercept some or all of the fetch requests of the web page, and then see if the files requested by these requests are in our cache. If so, we can take them directly from the cache without downloading them. This is one of the most important functions of the PWA.

self.addEventListener('fetch'.function (event) {
    event.respondWith(
        caches.match(event.request)
        .then(function (response) {

            if (response) {
                return response;
            }

            var fetchRequest = event.request.clone();

            return fetch(fetchRequest).then(
                function (response) {

                    if(! response || response.status ! = =200|| response.type ! = ='basic') {
                        return response;
                    }

                    var responseToCache = response.clone();

                    caches.open('v1')
                        .then(function (cache) {
                            cache.put(event.request, responseToCache);
                        });

                    returnresponse; }); })); });Copy the code

First, the FETCH event is called when a FETCH request is made. The event of the FETCH event also has a special attribute, that is request. Similar to the request in NodeJS, it represents a request.

We first check the cache to see if the request has been stored before, and call the match function, which returns a Promise, which calls a response callback when it succeeds. If the file corresponding to the request is found in the cache, then the response is not undefined, so it can be returned directly.

The problem is, how do we tell the main thread: “This file was downloaded, it’s in my cache, just come and get it.” There’s another method inside event, which is the event.respondwith method. It accepts as an argument a Promise whose successful callback should be a response.

If not, we need to download it from the server, but we also want to cache it so that we don’t have to download it every time.

An important reason for using FETCH rather than Ajax is that FETCH naturally supports Request and Response and uses promises. This is the same as service workers.

Fetch receives a request as a request and returns a response to the request in the callback function.

Note that both Request and Response are streams, similar to a NodeJS Stream. So if we pass event. Request directly to fetch, then request cannot be reused. So let’s copy a request so we can reuse it. When a fetch succeeds (a successful request does not mean that the data has been retrieved, unlike Ajax, it is not successful only when an error occurs that causes the request to fail. In other cases, even if the request is 404, it is still successful), we check whether the response received anything, and it is 200 successful, and it cannot be cross-domain (i.e. response.type == ‘basic’).

Ok, now that we have this response from the server, we just need to add it to our cache. Here we call cache.put to cache the response to the request.

And finally, don’t forget to return this response! And for reuse, the return should be clone! Because event.respondWith needs to tell the main thread: “We have received this request (whether from the cache or from the server), you just accept the response!”

everything

We’re all set up now, so let’s see if it works. Open the terminal and run the server script

nodejs ./server.js
Copy the code

Open localhost:8080 and unsurprisingly you should see PWA! .

Now let’s stop the server script and refresh the page again. The page should also show PWA! .

Some of the problems

  1. How do I update the service Worker?

    It’s easy, you just change sw.js, it will detect and compare the next time you connect to the Internet, and if it’s different, it will reinstall.

  2. How do I update cached scripts or files?

    You can develop an interface to check for updates and then manually request and update parts of the file

  3. Are there any success stories to learn from?

    Yes, use Chrome to open the Vue Chinese official website, it will prompt you to join the desktop, after agreeing, you will find the magic of PWA.

  4. Why is my PWA not supported on my phone?

    You need to install Chrome or Firefox and grant it some basic permissions, such as allowing you to create desktop ICONS

  5. Pwa doesn’t seem to have anything to do with offline access.

    No! Pwa is more than that! Pwa can even call some interfaces that native apps can call, and push messages like native apps!

  6. Great! How can I keep studying!

    You have two choices, MDN has documentation but simplified Chinese does not, only traditional Chinese. PWA official website, need science online.