PWA
介绍
说明,我只是简单介绍,并没有太深入,但深度还是有的
PWA 简称:Progressive Web App
特点:
- 可靠:网络不稳定,也能瞬间加载和展现
- 快速响应:用户操作后的响应非常快速
- 粘性:像原生应用一样,沉浸式(可以添加到桌面,推送服务)
用的技术栈:
- manifest.json
- service worker
- cache api
- background services(Fetch && Sync)(后台同步)
manifest 文件
manifest 文件控制了当 web app 安装到移动端的时候,应该怎么表现。这是一个完整的 manifest.json 文件示例:
{
"short_name": "Maps",
"name": "Google Maps",
"icons": [
{
"src": "/images/icons-192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/images/icons-512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/maps/?source=pwa",
"background_color": "#3367D6",
"display": "standalone", // fullscreen,standalone,minimal-ui,browser
// "orientation": "landscape",
"scope": "/maps/",
"theme_color": "#3367D6"
}
下面是name
参数的示例:
下面是background-color
参数的示例:
下面是theme-color
参数的示例:
下面是引入 manifest
文件的方法:
<!-- index.html -->
<link rel="manifest" href="/manifest.json">
当然我们也可以利用 meta
更改 theme-color
:
// 更改 theme-color 的 meta
<meta name="theme-color" content="#4285f4">
service worker
service worker,简称 SW ,有 3 个坑:
- 虽然 SW 只能在
https
环境下运行,但是它也能在localhost
或者217.0.0.1
这个 host 下运行。 - SW 是有作用域的,作用域是 SW 注册文件的放置目录。
- SW 从下载到激活再到代理 http 请求是有延迟性的。
SW 的作用域
比如说如果项目主目录是 ./,然后 sw.js 的文件目录是 ./foo/sw.js,那么 SW 的作用域就是 foo,它只能处理 /foo/xxxx 这个地址下的 http 请求。(最佳实践:把 sw.js 放在主目录下面,即放到这个文件目录:./sw.js)。
SW 的生命周期
下面是 SW 的生命周期:
- install: 当 SW 下载完成之后,就会执行 install,安装 SW。注意,在这个阶段,SW 对页面是不起作用的,并不能代理 http 请求。
- active: 当 SW 安装完成之后,并不会立即适用,它会在下次页面刷新或者打开的时候才会适用,所以初次打开页面的时候 SW 并不能代理 http 请求。如果这个时候页面已经有老的 SW,那么老的 SW 仍然会继续运行。
- waiting: 在 install 和 active 之间 SW 是属于 waiting 阶段,这个严格来说并不是生命周期,因为它没有一个回调。
下面是一个新的 SW 生命周期示意图:
下面是一个新的 SW 取代旧的 SW 的示意图:
SW 的调试
参见我的具体操作。
简单制作 PWA
说明目的
实际体验一下 pwa 的缓存效果和基本操作
- 注册 SW(self.skipWaiting 的使用)
- 缓存离线页(缓存离线页,判断请求来源,请求失败则跳转离线页)
- 缓存 app 请求
- SW 的延迟性
web push
说明目的
实际体验一下 web push 的实际 coding 过程 和原理
- 浏览器向服务端请求 web app。
- 服务端返回 web app 给客户端,同时浏览器安装 SW。
- 浏览器的 SW 向 google cloud 注册 push 功能。(需要翻墙)
- google cloud 返回给浏览器 token。
- 浏览器把 token 发送给 服务端。
- 服务端给浏览器返回消息确认 token 已收到。
- 当服务端需要进行 web push 的时候,把 push 内容发送给 google cloud,然后 google cloud 推送给浏览器。(需要翻墙)
实际应用
谷歌有一款插件叫做workbox.js。它使用的缓存策略是:
- StaleWhileRevalidate:同时从网络与缓存获取,如果缓存可用,取缓存数据,同时会把网络请求的数据缓存起来;否则从网络中请求,并更新缓存。
- CacheFirst(缓存优先):优先取缓存中的数据,若没有则请求网络,请网络也失败就会报错。
- NetworkFirst(网络优先):优先从网络获取,若没有则从缓存中获取,缓存获取失败则报错。
- CacheOnly(仅缓存):只从缓存中获取,若没有则报错。
- NetworkOnly(仅网络):只从网络获取,若没有则报错。
Vue 官方文档的刷新小窗原理
workbox.js
自己实现了很多钩子,其中就有update
钩子(详细见文档What is Broadcast Update?),这是专门针对StaleWhileRevalidate所做的钩子,因为这个缓存策略在使用缓存的时候,同时也会发出网络请求,请求最新数据,当所有的数据请求完成之后,它会判断新的缓存和旧的缓存是否有变动,如果有的话,就广播 update 事件。然后 Vue 官方文档监听了 update 事件,如果监听到了,就弹出小窗让我们刷新。
官方插件
Vue 官方 对上面的 workbox.js
做了一定的封装,开发了 @vue/cli-plugin-pwa 插件,这个插件仅仅是做简单的封装而已,需要我们自己配置缓存策略。
Nuxt 官方 也对上面的 workbox.js
做了一定的封装,开发了@nuxtjs/pwa 插件,这个插件使用的缓存策略是:
- 对 webpack 没有打包的资源(static 文件夹):网络优先
- 对 webpack 打包的资源(_nuxt 文件夹):缓存优先
结合我们的项目
- 官网项目:需要,不解释。
- 后台项目:api 请求是实时的,不需要;对于静态资源,可以考虑缓存 js,css 和 字体(但是有其它更好的储存方法)。
目前的困境
PWA 虽然有这么棒的离线体验,但是它还没有得到广泛的运用,原因有以下几点:
- iOS11.3 之前都不支持
- web push 需要客户端翻墙来连接 GCM(Google Cloud Messaging)
- 微信小程序的竞争