In the react, cra2, and typescript PWA project from development to deployment (1), we learned what create-React-app provides for PWA support and what it lacks. Although create-react-app will automatically generate a service-worker.js to cache our app shell, there is no way for developers to customize service workers, unless we eject the project. This article continues, Share what you’ve learned in this project.

Project review

This is a mobile PWA app that uses React, typescript, react-redux, react-router, and workbox. Can be added to the main screen, can be disconnected under normal conditions to open and access data. Project address: browseExpbyReact

Use the typescript

Typescript is a superset of JavaScript. On the one hand, we can use the latest features in typescript. On the other hand, typescript gives us a type system that allows us to write robust code and avoid potential runtime errors. Use typescript in create-react-app. The ts version of create-react-app is recommended to configure typescript for you. Use react-script-ts instead of react-script to drive the project. However, this version of the update will be slightly behind the original, and it does not allow us to extend the scaffolding configuration, so it is not recommended. We use react-app-rewired for configuration.

Thank you for reminding us: October 29, 2018 v2.1.0 adds support for typescript with Bebal7. Now we can run create-react-app my-app typescript to support typescript. So if you look at create-react-app you can get an update to create-react-app, but then you need to re-app-rewired in this project, We need it to modify our default Workbox Webpack plugin configuration.

The role of the react – app – rewired

There are two common ways to change the default configuration in create-react-app.

  1. One is the Eject project, where eject exposes the configuration in our scaffolding so we can modify it, but this is an irreversible process, and exposing the configuration is not an elegant practice, so it’s not recommended.
  2. The second option is to use react-app-rewired to modify our configuration, which allows us to modify our configuration without eject projects. For example, we can configure typescript by finding the react-app-rewire-typescript plugin. Please refer to this project for details

As of v2.1.0, react-app-rewire-typescript is no longer required to configure typescript support. Just run create-react-app my-app –typescript to get typescript support. If you are using CRA v2.1.0 or later, you can ignore the configuration of typescript in this article.

Use WorkBox to customize your own service worker

This brings us to the focus of this article: how to customize your own service-worker.js in create-react-app. The current CRA references the Workbox Webpack Plugin in place of the previous SW-Precach-webpack-plugin. We can override the default Workbox Webpack plugin configuration with react-app-rewired. Main steps:

  1. Modify the Workbox webpack plugin configuration in config.overrides. Js in the react-app-rewired configuration file
  2. Create your own service-worker profile in the public file directory

Replace the default workbox-webpack-plugin configuration with config.overrides.

/* config-overrides.js */
// typescript configuration plug-in
const rewireTypescript = require('react-app-rewire-typescript');
const workboxPlugin = require('workbox-webpack-plugin')
const path = require('path')

module.exports = {
  webpack: function (config, env) {
     // typescript configuration plug-in
    config = rewireTypescript(config, env);
    if (env === 'production') {
      // Add your own configuration in 'Production' mode
      const workboxConfigProd = {
        swSrc: path.join(__dirname, 'public'.'cus-service-worker.js'),
        swDest: 'cus-service-worker.js'.importWorkboxFrom: 'disabled'
      }
      Delete the default WorkboxWebpackPlugin configuration
      config = removePreWorkboxWebpackPluginConfig(config)
     // Add our configuration
      config.plugins.push(new workboxPlugin.InjectManifest(workboxConfigProd))
    }
    return config
  }
}
This function is used to find the WorkboxWebpackPlugin in the default configuration and remove it
function removePreWorkboxWebpackPluginConfig (config) {
  const preWorkboxPluginIndex = config.plugins.findIndex((element) = > {
    return Object.getPrototypeOf(element).constructor.name === 'GenerateSW'
  })
  if(preWorkboxPluginIndex ! = =- 1) {
    config.plugins.splice(preWorkboxPluginIndex, 1)}return config
}
Copy the code

This part of the configuration basically means that when the environment is a build environment, find the webpack configuration for workbox-webpack-plugin, delete it, and replace it with your own configuration.

Here to explain removePreWorkboxWebpackPluginConfig this function. We can create a new useless project ourselves with create-react-app, and then eject it, Then we can see the configuration of workbox-webpack-plugin in webpack.config.prod.js under the exposed config folder

new WorkboxWebpackPlugin.GenerateSW({
      clientsClaim: true.exclude: [/\.map$/, /asset-manifest\.json$/],
      importWorkboxFrom: 'cdn'.navigateFallback: publicUrl + '/index.html'.navigateFallbackBlacklist: [
        // Exclude URLs starting with /_, as they're likely an API call
        new RegExp('^ / _'),
        // Exclude URLs containing a dot, as they're likely a resource in
        // public/ and not a SPA route
        new RegExp('/ [^ /] + \ \ [^ /] + $')]}),Copy the code

So we can find the location of this configuration using the following code:

// Call the plugins array to findIndex to find the constructor member whose name attribute is' GenerateSW '
const preWorkboxPluginIndex = config.plugins.findIndex((element) = > {
    return Object.getPrototypeOf(element).constructor.name === 'GenerateSW'
  })
// Delete this member
  if(preWorkboxPluginIndex ! = =- 1) {
    config.plugins.splice(preWorkboxPluginIndex, 1)}Copy the code

After replacing the workbox-webpack-plugin configuration, create the cus-service-worker.js file in the public directory according to your own configuration. This file will replace the default service-worker.js file. We can customize our own PWA configuration by configuring cus-service-worker.js, and the content in cus-service-worker.js is also exquisite. Take this project as an example:

// Introduce the workbox global variable
importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.4.1/workbox-sw.js');

if (workbox) {
  console.log(`Yay! Workbox is the loaded 🎉 `);
} else {
  console.log(`Boo! Workbox didn 't load 😬 `);
}
// set the prefix and suffix of our sw's name
workbox.core.setCacheNameDetails({
  prefix: 'browse-exp'.suffix: 'v1.0.0'});// have our sw update and control a web page as soon as possible.
workbox.skipWaiting();
workbox.clientsClaim();

// Precache static resources
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

// Customize your own requirements
// cache our data, and use networkFirst strategy.
workbox.routing.registerRoute(
  new RegExp('.*experiments\? . * '), 
  workbox.strategies.networkFirst()
);
workbox.routing.registerRoute(
  new RegExp('.*experiments/\\d'),
  workbox.strategies.networkFirst()  
)
workbox.routing.registerRoute(
  new RegExp('.*experiment_types.*'),
  workbox.strategies.networkFirst()
)

Copy the code

The workbox global variable is first introduced via importScripts. At packaging time, the scaffold generates a precach-manifest list for us, which lists a list of static files that we can get from self.__precachemanifest, so we need to pre-cache these static resources with the following statement:

self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
Copy the code

To get our service worker to control the page as quickly as possible, we can add the following statement at the beginning:

// Skip the wait
workbox.skipWaiting();
// Control the client
workbox.clientsClaim();
Copy the code

The rest of the network can be used according to their own needs, such as the need to configure any function, in this case, I cache the route to obtain data, using networkFirst policy, what is networkFirst policy? The network request is made first, and if it fails, the cached data is used.

When we package the project, we will find that the cus-service-worker.js file will be generated under the build file, and it will start with the following sentence:

importScripts("/precache-manifest.cd8115bc0ff644d6d74bec08ffcbdeb4.js");
Copy the code

This is why we can get the pre-cached list with self.__precachemanifest.

So far: we can customize our own service-worker.js.

manifest.json

Manifest.json allows you to add your web app to the desktop, and configure the manifest in create-react-app. It is easy to configure the manifest in the manifest.json directory in the public directory. The manifest.json configuration does not take effect immediately. You will be prompted to add it to your desktop only when you enter the page several times using HTTPS.

Conclusion:

  1. Rewrite our configuration with react-app-rewired
  2. Replace the default WorkboxWebpackPlugin configuration in config.overrides
  3. Write your own PWA configuration in the public directory

At this point we can customize our own PWA configuration in the scaffolding generated by create-React-app, which I’ll continue in the next article:

  1. How to Deploy Deploy the project to the Nginx server.
  2. Configure certificates for it to run over the HTTPS protocol.
  3. Experience the PWA project.

Interested students can scan the following TWO-DIMENSIONAL code to experience the project:

note:

  1. You are advised to open it in a UC browser because the UC browser supports PWA.
  2. The “Add to desktop prompt” is triggered by entering the Web app several times within a short period of time

If you are interested, compare this to the VUE based implementation: browseExpByVue