独立的 worker 线程,独立的 worker context
一旦被 install 就永远存在,除非被 uninstall
需要的时候可以直接唤醒,不需要的时候自动睡眠
可编程拦截代理请求和返回,缓存文件
消息推送,不操作DOM
Chrome V40 +
Firefox,Opera
Android Browser 4.x +
Android Chrome
iOS 。。
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js', {scope: '/'})
.then(function (registration) {
// 注册成功
console.log('ServiceWorker registration successful with scope: ', registration.scope);
})
.catch(function (err) {
// 注册失败:(
console.log('ServiceWorker registration failed: ', err);
});
});
}
this.addEventListener('install', function (event) {
event.waitUntil(
caches.open('my-test-cache-v1').then(function (cache) {
return cache.addAll([
'/',
'/index.html',
'/main.css',
'/main.js',
'/image.jpg'
]);
})
);
});
this.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request).then(function (response) {
// 如果 Service Worker 有自己的返回,就直接返回,减少一次 http 请求
if (response) {
return response;
}
// 如果 service worker 没有返回,那就得直接请求真实远程服务
var request = event.request.clone(); // 把原始请求拷过来
return fetch(request).then(function (httpRes) {
if (!httpRes || httpRes.status !== 200) {
return httpRes;
}
// 请求成功的话,将请求缓存起来。
var responseClone = httpRes.clone();
caches.open('my-test-cache-v1').then(function (cache) {
cache.put(event.request, responseClone);
});
return httpRes;
});
})
);
});
// 安装阶段跳过等待,直接进入 active
self.addEventListener('install', function (event) {
event.waitUntil(self.skipWaiting());
});
self.addEventListener('activate', function (evnet) {
event.waitUntil(
Promise.all([
// 更新客户端
self.clients.claim(),
// 清理旧版本
caches.keys().then(function (cacheList) {
return Promise.all(
cacheList.map(function (cacheName) {
if (cacheName !== 'my-test-cache-v1') {
return caches.delete(cacheName);
}
})
);
})
])
);
});
var cacheName = 'shell-content';
var filesToCache = [
'/css/styles.css',
'/js/scripts.js',
'/images/logo.svg',
'/offline.html',
'/'
];
self.addEventListener('install', function (e) {
console.log('[ServiceWorker] Install');
e.waitUntil(
caches.open(cacheName).then(function (cache) {
console.log('[ServiceWorker] Caching app shell');
return cache.addAll(filesToCache);
})
);
});
{
"name": "这是一个完整名称",
"icons": [
{
"url": "path-to-images/logo-144x144.png",
"type": "image/png",
"sizes": "144x144"
}
],
"background_color": "#2196f3",
"display": "standalone"
}
<link rel="manifest" href="path-to-manifest/manifest.json">
display: {string}
showNotification()
弹出通知function execute() {
registerServiceWorker()
.then(registration => {
registration
.showNotification('Hello World!', options);
});
}
{
// 视觉相关
"body": "<String>",
"icon": "<URL String>",
"image": "<URL String>",
"badge": "<URL String>",
"vibrate": "<Array of Integers>",
"sound": "<URL String>",
"dir": "<String of 'auto' | 'ltr' | 'rtl'>",
// 行为相关
"tag": "<String>",
"data": "<Anything>",
"requireInteraction": "<boolean>",
"renotify": "<Boolean>",
"silent": "<Boolean>",
// 视觉行为均会影响
"actions": "<Array of Strings>",
// 定时发送时间戳
"timestamp": "<Long>"
}
$ npm install -g lavas
$ lavas init & cd pwa-demo
$ npm install
$ npm run dev
pwa-project/ (项目根目录)
| - build/ (Webpack 和 dev-server 相关调试和构建配置文件)
| - config/ (通用模块配置)
| - src/ (源代码)
| - assets/ (依赖的静态资源)
| - components/ (业务开发的 Vue Component)
| - pages/ (具体业务开发的 Page 页面 Component)
| - store/ (Vuex store)
| - app.js (Vue 入口执行文件)
| - App.vue (项目的根 Component)
| - entry-client.js (前端渲染入口文件)
| - entry-skeleton.js(skeleton 渲染入口)
| - router.js (Vue-router 路由配置文件)
| - sw-register.js (注册 service worker 文件入口)
| - static/ (不需要经过构建的一些静态资源)
| - index.html
| - package.json
$ npm run build
/dist/service-worker.js
/* sw-precache.js中的配置 */
build: {
cacheId: 'my-vue-app',
// 生成的文件名称
filename: 'service-worker.js',
// 需缓存的文件配置, 可以逐项添加, 需动态缓存的放到runtimeCaching中处理
staticFileGlobs: [
// 'dist/index.html',
// 'dist/static/**/**.*'
],
// 忽略的文件
staticFileGlobsIgnorePatterns: [
/\.map$/ // map文件不需要缓存
],
// 当请求路径不在缓存里的返回,对于单页应用来说,入口点是一样的
navigateFallback: '/index.html',
// 白名单包含所有的.html (for HTML imports) 和路径中含 `/data/`
navigateFallbackWhitelist: [/^(?!.*\.html$|\/data\/).*/],
// 最大缓存大小
maximumFileSizeToCacheInBytes: 4194304,
}
/* sw-precache.js中的配置 */
build: {
// 生成service-worker.js的文件配置模板,不配置时采用默认的配置
// 本demo做了sw的更新策略,所以在原有模板基础做了相应的修改
templateFilePath: 'config/sw.tmpl.js',
// 需要根据路由动态处理的文件
runtimeCaching: [
]
}
// webpack.prod.conf.js 中通过组件引入配置,生成文件
new SWPrecacheWebpackPlugin(config.swPrecache.build);
config/sw.tmpl.js
src/components
├── AppBottomNavigator.vue
├── AppHeader.vue
├── AppMask.vue
├── AppSidebar.vue
├── ProgressBar.vue
└── Sidebar.vue
/src/store/modules/app-shell.js
mapStates() mapActions() - state, actions, mutations