基本知识普及请参考
https://www.jianshu.com/p/623...
https://zhuanlan.zhihu.com/p/...
下面简单介绍一下插件的使用
以下是我在项目中使用的配置
webpack.prod.conf.js中
{
...
plugins: [
new OfflinePlugin({
responseStrategy: 'cache-first', // 缓存优先
AppCache: false, // 不启用appCache
safeToUseOptionalCaches: true, // Removes warning for about `additional` section usage
autoUpdate: true, // 自动更新
caches: { // webpack打包后需要换的文件正则匹配
main: [
'**/*.js',
'**/*.css',
/\.(png|jpe?g|gif|svg)(\?.*)?$/,
/\.(woff2?|eot|ttf|otf)(\?.*)?$/
],
additional: [
':externals:'
]
},
externals: [], // 设置外部链接,例如配置http://hello.com/getuser,那么在请求这个接口的时候就会进行接口缓存
excludes: ['**/.*', '**/*.map', '**/*.gz', '**/manifest-last.json'], // 需要过滤的文件
ServiceWorker: {
output: './static/sw.js', // 输出目录
publicPath: '/static/sw.js', // sw.js 加载路径
scope: '/', // 作用域(此处有坑)
minify: true, // 开启压缩
events: true // 当sw状态改变时候发射对应事件
}
})
]
}
在入口js文件中
OfflinePluginRuntime.install({
// 监听sw事件,当更新ready的时候,调用applyUpdate以跳过等待,新的sw立即接替老的sw
onUpdateReady: () => {
console.log('SW Event:', 'onUpdateReady')
OfflinePluginRuntime.applyUpdate()
},
onUpdated: () => {
console.log('SW Event:', 'onUpdated')
window.swUpdate = true
}
})
首先介绍一下assets里面的三个属性:
main: [] 这里配置的是serviceWorker在install阶段需要缓存的文件清单,如果其中有一个失败了,那么整个serviceWorder就会安装失败,所以必须谨慎配置
additional: [] 这里配置的文件清单会在serviceWorker activate的时候进行缓存,与main不一样,如果这里的文件缓存失败,不会影响serviceWorker的正常安装。而且,在接下来页面的ajax异步请求中,还能进行缓存尝试
optional: [] 这里配置的文件清单在serviceWorker安装激活阶段不会进行缓存,只有在监听到网络请求的时候才进行缓存。
刚才说到作用域的时候有坑,如果按照上面的文件配置,最后在网页中会提示,sw最大的作用域权限在/static下面,言外之意这么写是无法将sw的作用域设置在/根路径下面。
所以这边需要服务端在返回sw.js的时候手动设置Service-Worker-Allowed头字段,并且值设置为/,同时这个文件的缓存时间设为0,否则,当更新serviceWorker的时候,由于浏览器缓存了sw.js用户端这边的serviceWorker无法第一时间更新。
最后来一张线上项目,在网速极慢的情况下也能实现秒开
-------------------追加--------------------扩展fetch事件
首先在配置文件里添加入口
sw-entry.js
self.addEventListener('fetch', function (event) {
function cachesMatch (request, cacheName) {
return caches.match(request, {
cacheName: cacheName
}).then(function (response) {
return response
})
// Return void if error happened (cache not found)
['catch'](function () {})
}
function cacheFirst(cacheUrl, CACHE_NAME) {
var resource = cachesMatch(cacheUrl, CACHE_NAME).then(function (response) {
if (response) {
return response;
}
// Load and cache known assets
var fetching = fetch(urlString).then(function (response) {
if (!response.ok) {
return response;
}
(function () {
var responseClone = response.clone();
var storing = caches.open(CACHE_NAME).then(function (cache) {
return cache.put(urlString, responseClone);
}).then(function () {
console.log('[SW]:', 'Cache asset: ' + urlString);
});
event.waitUntil(storing);
})();
return response;
});
return fetching;
})
return resource
}
function netWorkFirst(cacheUrl, CACHE_NAME) {
var resource = fetch(cacheUrl).then(response => {
if (response.ok) {
var responseClone = response.clone()
var storing = caches.open(CACHE_NAME).then(function (cache) {
cache.put(cacheUrl, responseClone);
}).then(function () {
console.log('[SW]:', 'Cache asset: ' + cacheUrl);
});
event.waitUntil(storing);
return response;
}
// Throw to reach the code in the catch below
throw new Error('Response is not ok');
})
['catch'](function () {
return cachesMatch(cacheUrl, CACHE_NAME);
});
return resource
}
var url = new URL(event.request.url)
url.hash = ''
var pathname = url.pathname
var urlString = url.toString()
var cacheUrl = urlString
var IS_KANO = /kano\.guahao\.cn/
var IS_STATIC = /\/static\//
var IS_HOME = /^\/(e|u|n)\/(\d+)$/
var IS_EDITOR = /^\/editor(?!\.)/
var IS_PREVIEW = /^\/preview(?!\.)/
var CACHE_PREFIX = __wpo.name
var CACHE_TAG = __wpo.version
var CACHE_NAME = CACHE_PREFIX + ':' + CACHE_TAG
var resource = undefined
var isGET = event.request.method === 'GET'
// 以缓存优先的形式缓存 kano 以及 static/* 静态资源
if ((cacheUrl.match(IS_KANO) || pathname.match(IS_STATIC)) && isGET) {
resource = cacheFirst(cacheUrl, CACHE_NAME)
event.respondWith(resource)
}
// 以网络优先的形式缓存 editor页面 preview页面和 production页面
if ((pathname.match(IS_HOME) || pathname.match(IS_EDITOR) || pathname.match(IS_PREVIEW)) && isGET) {
resource = netWorkFirst(cacheUrl, CACHE_NAME)
event.respondWith(resource)
}
})
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。