<script> if (window.addEventListener) { // 不允许缓存 service-worker.js 因为如果index.html被缓存了,可能导致 service-worker.js不更新 window.addEventListener("load", function() { // <script src="/js/service-worker.js?t=xxx"><//script> var script = document.createElement("script") script.src = `/js/service-worker.js?t=${new Date().getTime()}` script.async = true; script.type = "text/javascript"; script.crossOrigin = "anonymous"; document.head.insertBefore(script, document.head.firstChild) }) }</script>
// /js/service-worker.js(function(){ /* 使用动态生成 new webpack.DefinePlugin({ 'process.env.cacheStorageKey': `'${new Date().toISOString()}'` }) */ const version = new Date().toISOString() function register () { if ('serviceWorker' in navigator) { // 不允许 service-sw.js 被缓存 const url = `/service-sw.js?v=${version}`; navigator.serviceWorker.register(url).then((registration) => { var sw = null; var state if (registration.installing) { sw = registration.installing state = 'installing' } else if (registration.waiting) { sw = registration.waiting state = 'installed' } else if (registration.active) { sw = registration.active state = 'activated' } state && console.log(`sw state is ${state}`) if (sw) { sw.onstatechange = function () { console.log(`sw state is ${sw.state}`) } } }).catch((err) => { console.error('sw fail', err) }) } } function unRegister() { if ('serviceWorker' in navigator) { navigator.serviceWorker.ready.then(swReg => { swReg.unregister(result => { result && console.log("注销 Service Worker 成功") }) }) } } if (fetch) { fetch("开关接口地址").then(status => { if (status === 'on') { register() } else if (status === 'off') { unRegister() } }) }})()
/service-sw.js/*self: 表示 Service Worker 作用域, 也是全局变量caches: 表示缓存skipWaiting: 表示强制当前处在 waiting 状态的脚本进入 activate 状态clients: 表示 Service Worker 接管的页面*/// 缓存静态资源的key// 当页面发生修改时, 要同时对 cacheStorageKey 进行修改// 然后重新打开一次页面, 这个时候渲染的页面依然是旧的, 不过可以从 DevTools 看到 此 service work 被安装和激活。// 之后关闭页面, 再次打开, 就可以见到新的内容了。const cacheStorageKey = process.env.cacheStorageKey/*const ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin')使用 webpacknew ServiceWorkerWebpackPlugin({ // 注意这个项,打包时这个会加上webpack output.path // 期望生成目录时 /static 目录 filename: '/static/impl-service-sw.js', entry: path.resolve(__dirname, './static/service-sw.js')}),使用 webpack 动态生成 serviceWorkerOption.assets*/const cacheList = serviceWorkerOption.assets// sw.js self === windowself.addEventListener('install', function (e) { // 缓存静态资源 e.waitUntil( caches.open(cacheStorageKey) .then(cache => cache.addAll(cacheList)) .then(() => self.skipWaiting()) )})self.addEventListener('activate', function (e) { console.log('activate callback') // 更新缓存资源,清除缓存 const promises = caches.keys().then(cacheNames => { console.log('cacheNames', cacheNames) return cacheNames.map(name => { console.log('name', name) if (name !== cacheStorageKey) { return caches.delete(name) } return Promise.resolve() }) }) e.waitUntil( promises.then(list => { return Promise.all( list ) }).then(() => { return self.clients.claim() }) )})self.addEventListener('fetch', (event) => { // abandon non-GET requests if (event.request.method !== 'GET') return let url = event.request.url event.respondWith( caches.open(cacheStorageKey) .then(cache => { return cache.match(event.request) .then(response => { if (response) { // return cached file console.log('cache fetch: ' + url) return response } // make network request return fetch(event.request) .then(newreq => { // console.log('network fetch: ' + url) if (newreq.ok) cache.put(event.request, newreq.clone()) return newreq }) // app is offline .catch(function (error) { console.error('Fetching failed:', error) throw error }) }) }) )})self.addEventListener('error', event => { // 上报错误信息 // 常用的属性: // event.message // event.filename // event.lineno // event.colno // event.error.stack console.log('sw:event.message', event.message, event.filename)})self.addEventListener('unhandledrejection', event => { // 上报错误信息 // 常用的属性: // event.reason console.log('sw:event.reason', event.reason)})