记一次基于react、cra2、typescript的pwa项目由开发到部署(二)

栏目: IOS · Android · 发布时间: 6年前

内容简介:在上一篇文章这是一个移动端的pwa应用,使用react,typescript,react-redux,react-router,workbox 基于create-react-app 开发。可以添加到主屏幕,可以断网条件下正常打开和访问数据。项目地址:typescript是JavaScript的超级,一方面在typescript中我们可以使用最新的特性,另一方面typescript给我们带来了类型系统,可以让我们写出健壮的代码,避免一些潜在的运行时错误。在create-react-app中使用typescr

在上一篇文章 记一次基于react、cra2、typescript的pwa项目由开发到部署(一) 中,我们了解到了create-react-app 给我们提供了哪些pwa支持,也了解到了有哪些不足。虽然create-react-app会帮我们自动生成一个service-worker.js 去缓存我们的app shell,但是并没有提供让开发者定制service worker的方法,除非我们eject项目,这篇文章继续往下讲,把在这个项目中学到的东西分享给大家。

项目回顾

这是一个移动端的pwa应用,使用react,typescript,react-redux,react-router,workbox 基于create-react-app 开发。可以添加到主屏幕,可以断网条件下正常打开和访问数据。项目地址: browseExpbyReact

记一次基于react、cra2、typescript的pwa项目由开发到部署(二)
记一次基于react、cra2、typescript的pwa项目由开发到部署(二)

使用typescript

typescript是JavaScript的超级,一方面在typescript中我们可以使用最新的特性,另一方面typescript给我们带来了类型系统,可以让我们写出健壮的代码,避免一些潜在的运行时错误。在create-react-app中使用typescript,官网推荐我们使用的是 create-react-app的ts版本 ,他会帮你配置好typescript的相关配置,并使用react-script-ts代替react-script来驱动项目。但是这个版本的更新会稍稍滞后于原版,而且也不利于我们扩展脚手架的配置,所以这里不推荐使用。我们使用 react-app-rewired 来进行配置。

react-app-rewired

在create-react-app中修改默认配置有两种常用的方法,

  1. 一种是 eject 项目,eject会把我们的脚手架中的配置暴露出来,然后我们就可以去修改了,但是这是一个不可逆的过程,而且讲配置暴露出来也是一个不优雅的做法,所以不推荐。
  2. 第二种就是利用 react-app-rewired 去修改我们的配置,他可以让我们在不eject项目的前提下修改我们的配置。比如配置typescript,我们可以找到对应的插件 react-app-rewire-typescript 进行配置。具体可参考本项目

利用workbox 定制自己的service worker

这里到了本文的重点:如何在create-react-app中定制自己的service-worker.js。目前的cra引用了Workbox webpack plugin 代替了先前的 sw-precache-webpack-plugin。我们可以借助 react-app-rewired 去改写默认的Workbox webpack plugin 配置。主要步骤:

  1. 在 react-app-rewired 的配置文件 config.overrides.js 中修改 Workbox webpack plugin的配置
  2. 在public文件目录下建立自己的service-worker配置文件

首先在 config.overrides.js 中配置,替换默认的workbox-webpack-plugin配置:

/* config-overrides.js */
// typescript的配置插件
const rewireTypescript = require('react-app-rewire-typescript');
const workboxPlugin = require('workbox-webpack-plugin')
const path = require('path')

module.exports = {
  webpack: function (config, env) {
     // typescript的配置插件
    config = rewireTypescript(config, env);
    if (env === 'production') {
      // 在 ‘production’ 模式下加入自己的配置
      const workboxConfigProd = {
        swSrc: path.join(__dirname, 'public', 'cus-service-worker.js'),
        swDest: 'cus-service-worker.js',
        importWorkboxFrom: 'disabled'
      }
      // 删除默认的WorkboxWebpackPlugin配置
      config = removePreWorkboxWebpackPluginConfig(config)
     // 加入我们的配置
      config.plugins.push(new workboxPlugin.InjectManifest(workboxConfigProd))
    }
    return config
  }
}
// 此函数用来找出 默认配置中的 WorkboxWebpackPlugin, 并把它删除
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
}
复制代码

这部分的配置大概意思就是,当环境为生成环境时,找出webpack中关于workbox-webpack-plugin的配置,把它删掉,然后用自己的配置替代它。

这里解释一下 removePreWorkboxWebpackPluginConfig 这个函数。我们可以自己用create-react-app新建一个无用的项目,然后eject它,那么我们可以在暴露出来的config文件夹下的 webpack.config.prod.js 中看到关于 workbox-webpack-plugin 的配置

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('/[^/]+\\.[^/]+$'),
      ],
    }),
复制代码

所以我们可以通过下面这段代码找到这段配置的位置:

// 对plugins数组调用findIndex方法,找到构造函数的name属性为‘GenerateSW’的成员
const preWorkboxPluginIndex = config.plugins.findIndex((element) => {
    return Object.getPrototypeOf(element).constructor.name === 'GenerateSW'
  })
// 删除这个成员
  if (preWorkboxPluginIndex !== -1) {
    config.plugins.splice(preWorkboxPluginIndex, 1)
  }
复制代码

替换掉workbox-webpack-plugin的配置后,根据自己的配置在public目录下新建cus-service-worker.js文件,这个文件会代替默认生成的service-worker.js文件,我们就可以通过配置cus-service-worker.js来定制自己的pwa配置了,而且cus-service-worker.js 里的内容也是有讲究的,以本项目为例:

// 引入workbox全局变量
importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.4.1/workbox-sw.js');

if (workbox) {
  console.log(`Yay! Workbox is loaded :tada:`);
} else {
  console.log(`Boo! Workbox didn't load :grimacing:`);
}
// 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();

// 将静态资源进行预缓存
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

// 定制自己的需求
// 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()
)

复制代码

首先通过importScripts 引入workbox全局变量。在打包的时候,脚手架会为我们生成一个 precache-manifest列表,里面会列举一系列的静态文件,我们可以通过 self.__precacheManifest 拿到这个列表, 所以我们需要通过一下语句预缓存这些静态资源:

self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
复制代码

然后就是为了尽快的让我们的service worker控制页面,我们可以在开头加入一下语句:

// 跳过等待
workbox.skipWaiting();
// 控制客户端
workbox.clientsClaim();
复制代码

剩下的部分自己就可以按自己的需求进行发挥了,像要什么功能就配置什么功能,这里的话我为自己获取数据的路由进行了缓存,采用的是 networkFirst 策略,什么是networkFirst策略呢?就是首先会进行网络请求,如果失败的话再使用缓存中的数据。

记一次基于react、cra2、typescript的pwa项目由开发到部署(二)

当我们打包项目的时候,就会发现再build文件下,会生成一个cus-service-worker.js文件,并且再开头多了一句:

importScripts("/precache-manifest.cd8115bc0ff644d6d74bec08ffcbdeb4.js");
复制代码

这就是我们可以通过 self.__precacheManifest 拿到预缓存列表的原因。

到目前为止:我们已经可以定制自己的service-worker.js了。

manifest.json

manifest.json可以让我们的web app添加到桌面,再create-react-app中配置manifest非常简单,直接再public目录下的manifest.json配置就可以了,关于什么么配置项,可以到这里谷歌官网教程查看,另外manifest.json的配置不会马上生效,需要在https协议下,多次进入该网页的时候才会弹出添加到桌面的提示。

总结:

  1. 利用 react-app-rewired 改写我们的配置
  2. 在 config.overrides.js 中替换默认的 WorkboxWebpackPlugin 的配置
  3. 在 public 目录下编写自己的pwa配置

到这里我们可以在create-react-app生成的脚手架中定制自己的pwa配置了,在 下一篇文章 中,我会继续讲解:

  1. 如何部署将该项目部署到nginx服务器上。
  2. 为它配置证书,让它运行在https协议上。
  3. 体验该pwa项目。

感兴趣的同学可以扫描下面二维码体验项目:

note:

  1. 建议用uc浏览器打开,因为uc浏览器对pwa的支持较好。
  2. "添加到桌面的提示" 需要短时间多次进入web app 才会触发
记一次基于react、cra2、typescript的pwa项目由开发到部署(二)

项目地址: browseExpByReact 如果感兴趣,可以对比着基于vue的实现来看: browseExpByVue


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Think Python

Think Python

Allen B. Downey / O'Reilly Media / 2012-8-23 / GBP 29.99

Think Python is an introduction to Python programming for students with no programming experience. It starts with the most basic concepts of programming, and is carefully designed to define all terms ......一起来看看 《Think Python》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具