Skip to content
used for registering pwa
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
design
docs
src
test
typings
webpack
.gitignore
.npmignore
README.md
nawa.d.ts
package.json
publish
tsconfig.json
webpack.config.js
webpack.prod.js

README.md

简介

现在,随着 PWA 在前端慢慢普及,本身的支持性可以完美的运行在现代浏览器当中,例如,Chrome、Firefox、UC 和 X5。iv-pwa 的核心理念就是让离线应用能够在 Web 中得到真正的应用和实践。该库是基于 sw-toolbox API 设计,抽离了几个基本的缓存策略方法。

  • cacheFirst: 优先走缓存,并且检查当前缓存是否超过有效期限,默认值是 2 天,这里可以根据具体的文件来设置。
  • cacheUpdate: 优先走缓存,并且会在每次返回缓存之后,额外进行后台更新。常常用于 HTML 资源文件。

另外,nawa 经由 webpack 编译,支持 es6/7 的语法模式。基本特性有:

  • 可以根据域名和路径实现区分匹配
  • 支持缓存 HTML 的完全离线
  • 非 HTML 资源根据 hash 检测缓存
  • 可配置离线策略
  • 使用最新 ES6 的语法

image.png-189.8kB

安装

腾讯内部开发者,使用 tnpm 进行下载:

tnpm install nawa --save

外部开发者,直接通过 npm 下载:

npm install nawa --save

上手使用

在完成项目的 install 之后,现在我们主要针对一个项目 now.qq.com/qq/market/index.html 来做接入。大致可以分为,初始化和缓存设置两步。该项目有个特点,就是可以实现全部离线的效果,并且在二次打开时会默认使用上一次更新的 HTML。

import Nawa from 'nawa';

# 设置基本缓存表
const cacheDB = "now-content";

let pwaControl = new Nawa({
  whiteList: ['now.qq.com/qq/market/index.html']
});

不过这里推荐直接使用配置文件的方式来进行接入,这样做能极大的提升开发效率,只需要 copy && paste 操作即可。

直接使用配置文件

如果觉得上面写法比较麻烦,可以直接使用一份�配置文档来实现 PWA 的上手配置。这里我们以常用 Now 业务来实现 PWA 的接入。

我们简单分析一下缓存策略,对文件进行分类:

  • cacheFirst: 使用 cacheFirst 策略进行匹配。JS/CSS 资源根据 hash 来进行匹配,验证其是否过期,对应的资源为:
cacheFirst:[{
            origin:"11.url.cn",
            path:[
                /now\/lib\/.*\.(?:js|css).*/,
                /now\/qq\/.*\.(?:js|css|png|jpeg|jpg|webp).*/
            ]
        },{
            origin:"open.mobile.qq.com",
            path:/sdk\/.*\.(?:js).*/
        }]
  • cacheFirstUpdate: 使用 cacheFirstUpdate 策略处理某些更新敏感的文件。它会首先返回缓存,然后再内部进行更新。常常处理 HTML 资源:
cacheFirstUpdate:[
            {
                origin:"now.qq.com",
                path:/.*\.(?:html).*/
            }
        ]

然后加上默认的 config 配置即可。整个文件可以直接参考[pwaconfig.js(http://git.code.oa.com/ivweb/nawa/tree/master/example) 最后使用 pwa 接入即可:

import PWALib from '@tencent/nawa';
import config from './pwa'; // load the profile


PWALib.create(config);

如果你要想通过编程来接入的话,我们就需要具体对某些 CDN 资源和 HTML 进行相关缓存路由设置。

缓存 CDN 域名资源

一般在站点部署时候,都会用上 CDN 节点来加速资源的发布,比如,你将相关静态的 JS | CSS | PNG 资源放在 11.url.cn 域名下。并且针对业务不同,放置在不同路径上:

# 缓存 11.url.cn/now/lib 路径下的 js 和 css 资源文件
pwaControl.cacheFirst(/now\/lib\/.*\.(?:js|css).*/, {
  origin: "11.url.cn",
});

# 缓存 11.url.cn/now/qq 路径下的 js 和 css 资源文件
pwaControl.cacheFirst(/now\/qq\/.*\.(?:js|css|png|jpeg|jpg|webp).*/, {
  origin: "11.url.cn",
});

离线应用部署

所谓的离线不离线,简单来说就是你的 HTML 资源是否被缓存。这里,可以针对业务不同,来设置你是否对 HTML 资源的缓存。如果打算对当前 HTML 进行离线部署,可以使用 cacheFirstUpdate 策略,在返回缓存之后,再对资源进行一次更新。

# 缓存当前 HTML 资源
pwaControl.cacheFirstUpdate(/.*\.(?:html).*/, {
  origin: "now.qq.com",
});

完整接入文件,可以直接参考:example docs

中间件捕获

这里针对 fetch 事件�添加了中间件的功能。如果你想对请求做相关的额外处理的话,可以通过中间件的形式来完成。不过,该功能主要针对有特殊需求的用户�使用。

pwaControl.use((request,next)=>{
    let {
        mode,
        url,
      } = request;
    
      // check that the requst is HTML or not
    if(!(/^http.*\.html/.test(url) && mode==="navigate")){
        // the request type is not HTML 
        next();
    }
})

通过 use 方法传递一个函数,里面的参数为:

  • request: event.request 请求对象
  • next: 是否执行下一个中间件,如果不执行则会在当前中间件停止。

更多可以直接参考 api docs

业务端接入

上面只是简述了一下,如何在 sw.js 中接入 PWA,但是,接入 PWA 还需要在主业务用耦合一小段代码,这里同样提供了一个方便的接入脚本。项目可以直接参考:nawa-register

api 文档

api docs

FAQ

  1. 如果是跨域资源,请求里面一定需要带上 cross-origin 的属性。例如:
<script type="text/javascript" crossorigin="anonymous" src="//11.url.cn/now/h5/index_ddc256d.js?_bid=152"></script>
  1. 主业务代码怎么接入呢?

可以参考 nawa-reigster 项目即可。

  1. 整个接入流程是什么呢?
  • 首先创建你的 sw.js,比如,在 Now 中直接在 now-qq-pwa 项目里面自己新建一份 sw.js 文件
  • 创建完毕后,在主业务中,使用 nawa-reigster 直接接入。
  1. 在创建 sw.js 时,只能在和 xxx.html 同自路径,比如 now.qq.com/h5/qq/test.html 只能新建一份 ow.qq.com/h5/qq/sw.js 文件。

  2. 使用 LRU 进行缓存管理有什么优势吗?

LRU 真正生效的是在�� CacheStorage 存储满的时候。这里有两种情况:

  • 使用 precache,一次性请求多个资源。�此时,由于 IndexDB 本身的限制,实际得到的结果为:x_amount = x0 + x_n - x_r
    • x0: 当前 IndexDB 里面存储的总量
    • x_n: 当前请求的资源数
    • x_r: indexDB 里面需要删除的数量。该数量一般是 maxCount*40%
  • 每次 fetch 捕获时,删除的公式为:x_amount = x0 + 1 - x_r
You can’t perform that action at this time.