Lidong's blog

PWA 备忘录

欢迎访问新站点: https://www.yidiankuaile.com/post/pwa-cheat-sheet

什么是 PWA

Wab App Manifest

<link rel="stylesheet" href="/manifast.json">

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
{
"name": "PWA Simple",
"short_name": "PWASimple",
"start_url": "/index.html",
"display": "standalone",
"background_color": "#FFE9D2",
"theme_color": "FFE1C4",
"orientation": "portrait-primary",
"icons": [
{
"src": "/icons/icons-72x72.png",
"type": "images/png",
"sizes": "72x72"
},
{
"src": "/icons/icons-96x96.png",
"type": "images/png",
"sizes": "96x96"
},
{
"src": "/icons/icons-128x128.png",
"type": "images/png",
"sizes": "128x128"
},
{
"src": "/icons/icons-144x144.png",
"type": "images/png",
"sizes": "144x144"
}
]
}

iOS 支持

1
2
3
<!-- iOS support -->
<link rel="apple-touch-icon" href="/icons/icon-96x96.png" />
<meta name="apple-mobile-web-app-status-bar" content="#aa7700" />

Service Worker

当第一次加载页面时,Service Worker 还没有激活,所以不会处理任何请求,只有当它安装和激活后,才能控制在其范围的一切。这意味着,只有刷新页面或导航到另一个页面,Service Worker 内的逻辑才会启动

注册 Service Worker

app.js
1
2
3
4
5
6
7
// register the service worker
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("/sw.js")
.then(reg => console.log("service worker registered", reg))
.catch(err => console.log("service worker not registered", err));
}

Service Worker 安装事件

在安装过程中预缓存

sw.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// install service worker
self.addEventListener("install", evt => {
evt.waitUntil(
// 使用指定的缓存名称打开缓存
caches
.open(staticCacheName)
// 将文件添加到缓存中
.then(cache => {
cache.addAll([
"/",
"/index.html",
"/about.html",
"manifest.json",
"/css/style.css"
]);
})
);
});

如果所有的文件都成功缓存,Service Worker 便会安装成功。如果有任何文件下载失败,那么安装过程也会随之失败。

检查传入的请求 URL 是否匹配当前缓存已有内容

sw.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// fetch event
self.addEventListener("fetch", function(event) {
event.respondWith(
// 检查传入的请求URL是否匹配当前缓存已有内容
caches.match(event.request).then(function(response) {
// 如果有 response 并且它不是未定的或空的,就返回
// 否则如往常一样继续,通过网络获取内容
if (response) {
return response;
}
return fetch(event.request);
})
);
});

拦截请求并缓存,适用于网页中动态链接

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
var cacheName = "hello";

self.addEventListener("fetch", function(event) {
event.respondWith(
// 检查传入的请求URL是否匹配当前缓存已有内容
caches.match(event.request).then(function(response) {
// 如果有response并且它不是未定的或空的,就返回缓存内容
if (response) {
return response;
}

// 复制请求,请求是一个流,只能使用一次
var requestToCache = event.request.clone();
return fetch(requestToCache).then(function(response) {
// 如果请求失败或者服务器响应了错误代码,则立即返回错误信息
if (!response || response.status !== 200) {
return response;
}

var requestToCache = response.clone();
caches.open(cacheName).then(function(cache) {
cache.put(requestToCache, requestToCache);
});
return response;
});

// 否则如往常一样继续,通过网络获取内容
return fetch(event.request);
})
);
});

Service Worker 更新

为了能让 Service Worker 做到实时更新,必须要解决 Service Worker 文件 sw.js HTTP 缓存的问题
服务端设置 Cache-Control

nginx.conf
1
2
3
4
location ~ \/sw\.js$ {
add_header Cache-Control no-store;
add_header Pragma no-cache;
}

更新记录

  1. 2019/7/23 19:58:21 首次发布

参考链接

  1. 如何优雅的为 PWA 注册 Service Worker
  2. Service Worker | Google Developers
  3. Service Worker 生命周期 | Google Developers
  4. 谨慎处理 Service Worker 的更新

本文链接:


评论内容还在加载中。。。
如无法加载,请将域名 disqus.com 和 disquscdn.com 加入到你的代理规则中