简介

●此处将“优雅”的含义定义为两个方面:
(1)应用webpack生态简化ServiceWorker的配置;
(2)ServiceWorker的开关控制与相关库的按需加载;
●第一方面具体是offline-plugin插件的应用;
●第二方面是动态获取前端配置与webpack的Code Spliting机制的应用;

offline-plugin插件的应用

○webpack生态提供了offline-plugin用于方便地使用ServiceWorker,首先在项目内安装此依赖;
○然后对offline-plugin进行配置与引入,分为以下两部分:
(1)作为webpack插件在项目webpack配置文件中增加此plugins的配置;
(2)作为js库在main.js中引入与实例化运行时对象;
○在ServiceWorker更新安装完成后强制生效通过在以上(1)部分配置”events:true”和在以上(2)部分中处理onUpdateReady和onUpdated两个事件回调实现;

动态获取前端配置

■为方便线上环境下必要时候关闭ServiceWorker机制,将ServiceWorker的开关配置在服务端,当前是否启用由从服务器获取到的开关取值决定;
■当获取到的开关值为false则进行ServiceWorker的注销以保证ServiceWorker的彻底关闭;

Code Spliting机制的应用

▲通过splitChunks将offline-plugin显式拆分为独立的chunk;
▲main.js中使用动态import的方式引入offline-plugin的运行时class;
▲如此实现了对offline-plugin的按需加载;

代码实例

◆webpack配置文件增加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
var OfflinePlugin = require('offline-plugin');

module.exports = {
……
optimization: {
……
splitChunks: {
minSize: 0, // 关掉独立chunk最小大小的限制
cacheGroups: {
offline: { // 将offline-plugin显式拆分成独立的chunk
test: /offline-plugin/,
name: 'offline',
chunks: 'all',
priority: 3
},
……
}
……
plugins: [
……
new OfflinePlugin({
AppCache: false, //`offline-plugin`默认支持`AppCache`,但是`AppCache`草案已经被web标准所废弃,不建议使用。但是由于仍然有部分浏览器支持,所以插件默认提供这个功能。
safeToUseOptionalCaches: true, // 去除`additional | optional`路径检查不确定时打印的警告
ServiceWorker: {
events: true //用于当前控制页面的sw的强制更新
},
caches: { //缓存内容的精细控制
main: ['index.html', '*/vconsole.min.js'],
additional: ['*/js/common.*.js', '*/js/app.*.js', '*/js/vendor.*.js'],
optional: [':rest:']
}
})
]
};

◆main.js文件增加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Service Worker
if ('serviceWorker' in navigator) {
if (config.serviceWorker) {// 从服务器获取到的ServiceWorker开关值
setTimeout(() => {// 防止干扰主程序初始化速度,将ServiceWorker的初始化放到主线程执行队列的队尾
console.log('serviceWorker init');
import('offline-plugin/runtime').then(swRuntime =>{
swRuntime.install({
onUpdateReady: () => {
console.log('sw onUpdateReady');
swRuntime.applyUpdate(); // 作用相当于原生ServiceWorker的self.skipWaiting()
},
onUpdated: () => { // 作用相当于原生ServiceWorker的监听 controllerchange 事件
console.log('sw onUpdated');
window.location.reload();
}
});
}, 0);
} else {
// 注销Service Worker时,使用如下片段:
navigator.serviceWorker.getRegistration().then(registration => {
registration &&
registration
.unregister()
.then(boolean => {
boolean ? console.log('Service Worker注销成功') : console.log('Service Worker注销失败');
})
.catch(error => {
console.log(`Service Worker注销异常:${error}`);
});
});
}
}