历时两个月,PWA功能终于在web端稳定落地使用,网站 web.itiger.com。
从最新研究到落地上线,遇到不少坑;开发过程中也参考了不少资料,但总有那么几个是没有答案,需要自己摸索结果的。所以,写了这篇总结文章,也阐述一下我在开发过程中遇到的问题,以及解决办法。
- 开发环境:vue+webpack,因为项目需要,vue版本v2.5.8,webpack版本v3.8.1
- Manifest.json配置
Manifest.json文件配置的属性是根据manifest的API完成的,其中稍作修改的有两处。改动的原因:webpack打包后的static文件路径(https://static.itiger.com)和真正的访问路径(https://web.itiger.com)是在两个不同的二级域名下,属于跨域,所以对manifest的icon和引入路径稍加配置。
(from: web.itiger.com )
1). icon的src属性配置
因为将Manifest.json文件放在static下,加上webpack的配置原因,icon图片的路劲会稍有不同,为了避免错误和麻烦,直接将图片转成了base64编码,也可以省去向服务器请求icon图片的时间,不占用带宽(如果图片较小,带宽的影响是可以忽略的)。
2). webpack打包后,manifest.json引入路径
Manifest.json是在index.html内用link标签引入的,如下所示:
<link rel="manifest" href="/manifest.json?<%=Date.now() %>">
(后面的参数:用打包时间做版本号识别)
但是manifest.json是放在/static文件夹下,经过webpack打包,正常来说也会在/dist/static文件夹下,但考虑上述提到的跨域问题,需要通过webpack(var CopyWebpackPlugin = require('copy-webpack-plugin'))引用依赖进行配置,将manifest.json文件打包到/dist目录下,便于访问。
plugins: [
new CopyWebpackPlugin([
{
from: resolve('static/manifest.json'),
to: resolve('dist/manifest.json')
}
])
]
- Service worker配置
Service worker 的安装注册,是跟所有教程一样的,不做赘述。可以在这里进行查阅。
在本项目中,静态缓存借用了workbox-webpack-plugins,service worker.js内有手写部分,所以没有采用workbox 的GenerateSW()方法自动生成,而是用的InjectManifest(),对已有的sw.js文件进行编辑。
因为workbox是存放在google的cdn上,考虑到客户翻墙问题,就把workbox下载并传到了tiger cdn上,所以,这边涉及到workbox的import问题:
如果是从google的cdn引入,则webpack配置时importWorkboxFrom : cdn;
如果是从项目本地引入,则importWorkboxFrom : local;
如果是从其他地方(如tiger cdn)引入,则importWorkboxFrom : disabled,并且在service worker.js文件内手动配置 importscript( ) 以及 workbox.core.setCacheNameDetails( ) 属性。
一开始,是考虑将workbox安装包放在项目内,但安装包不小,所以放弃了这种方法改用放在tiger cdn上。但是刚开始的配置是importWorkboxFrom : cdn,所以导致service worker.js文件中出现两个workbox的引入路径,造成引入失败;最终将importWorkboxFrom设置成disabled就解决了。
- IndexedDB和Cache Storage缓存清理
1). Cache storage实时更新数据时清除旧缓存
Cachestorage 中会有三个缓存,其中预缓存内容存放在***-precache内
在进行静态资源缓存时,缓存策略总会有选择staleWhileRevalidate()的时候,此时的请求结果缓存在***-runtime内,但会带来一个缓存问题。
用staleWhileRevalidate( )属性所配置的静态文件,会从cache storage访问,同时从network进行请求获得最新的数据并更新cache的内容
(from: developers.google.com/web/fundame…)
Runtime-cache的内容永远保持最新,但是之前的就缓存也没有被删除,会导致本地缓存量一直增加。
解决办法:每次service worker被激活时('activate',如刷新页面),新得到的请求结果在就缓存被删除后(waitUntil( ))再保存
this.addEventListener('activate', function(event) {
var cacheWhitelist = [workbox.core.cacheNames.runtime];
event.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (cacheWhitelist.indexOf(key) >= 0) {
return caches.delete(key);
}
}))
})
)
})
2). 清除缓存
当indexedDB和cache storage全部清空时,service worker.js 执行也不再有意义,所以要将service worker卸载,并重新改下载注册。
if (window.navigator && navigator.serviceWorker) {
navigator.serviceWorker.getRegistrations()
.then(registrations => {
for (let registration of registrations) {
registration.unregister()
}
})
}
卸载之后再清空indexedDB和cache storage
indexedDB.deleteDatabase('indexedDB的名称')
caches.keys().then((keyList) => {
if (!keyList.length) return
keyList.map((item) => {
caches.delete(item)
})
})
以上是该项目在落地PWA时遇到的一些坑和大家分享,有什么问题的欢迎指正。