前阵子制作了我的个人摄影网站 Tit1e’s Photo Studio。由于是网站,因此每次访问的时候总是有些麻烦,虽然现在移动端已经可以把书签添加至桌面,但是打开的时候依旧是浏览器的界面,丑丑的工具栏跟地址栏依旧显示在界面上,而且把书签添加到桌面这种操作也太没技术含量了,于是我想到了 PWA。这玩意儿我一直在用,但是自己从来没实践过,于是正好趁着这个机会实践一番,项目本身很简单,拿来试手正好。

我这个项目改造很简单,添加 PAW 插件:

1
2
# 如果没装脚手架,那需要先安装一下 vue-cli
vue add pwa

但是我执行这一步的时候报错了,原因是因为 node 版本过低,依赖冲突。我原本使用的是 9.6 版本的 node,不行。又换了 11.8 的版本,依旧冲突。最后我直接使用了最新的 15.5.1 的版本。

执行完成后,你的项目中会多出一些文件。

首先修改 vue.config.js,在配置文件中新增下列配置项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module.exports = {
pwa: {
manifestOptions: {
short_name: "Title's Album", // 名称缩写
name: "Title's Album", // 全名
start_url: "index.html", // 启动页面
display: "standalone", // 启动过渡动画
background_color: "#1f212b", // 背景颜色
theme_color: "#1f212b" // 主题颜色
},
iconPaths: {
favicon32: 'icon.png',
favicon16: 'icon.png',
appleTouchIcon: 'icon.png',
maskIcon: 'icon.png',
msTileImage: 'icon.png'
}
}
}

icon.png 就是之后添加到桌面后的图标,放置位置在 public 目录下。

然后在 public/index.htmlheader 中加入 <meta name="theme-color" content="#1f212b">

在 src 目录下新建 service-worker.js 文件:

下面的代码来自网上,我目前还不是很明白里面的缓存机制,如果不建这个文件,打包的时候 Vue 会自行生成一个 service-worker.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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");


workbox.core.setCacheNameDetails({
prefix: 'photo-album',
suffix: 'v1.1.1'
});

workbox.core.skipWaiting(); // 强制等待中的 Service Worker 被激活
workbox.core.clientsClaim(); // Service Worker 被激活后使其立即获得页面控制权

// 缓存web的css资源
workbox.routing.registerRoute(
// Cache CSS files
/.*\.css/,
// 使用缓存,但尽快在后台更新
workbox.strategies.staleWhileRevalidate({
// 使用自定义缓存名称
cacheName: 'css-cache'
})
);

// 缓存web的js资源
workbox.routing.registerRoute(
// 缓存JS文件
/.*\.js/,
// 使用缓存,但尽快在后台更新
workbox.strategies.staleWhileRevalidate({
// 使用自定义缓存名称
cacheName: 'js-cache'
})
);

// 缓存web的图片资源
workbox.routing.registerRoute(
/\.(?:png|gif|jpg|jpeg|svg)$/,
workbox.strategies.staleWhileRevalidate({
cacheName: 'images',
plugins: [
new workbox.expiration.Plugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60 // 设置缓存有效期为30天
})
]
})
);

// 我们很多资源在其他域名上,比如cdn、oss等,这里做单独处理,需要支持跨域
workbox.routing.registerRoute(
/^https:\/\/cdn\.my\.com\/.*\.(jpe?g|png|gif|svg)/,
workbox.strategies.staleWhileRevalidate({
cacheName: 'cdn-images',
plugins: [
new workbox.expiration.Plugin({
maxEntries: 60,
maxAgeSeconds: 5 * 24 * 60 * 60 // 设置缓存有效期为5天
})
],
fetchOptions: {
credentials: 'include' // 支持跨域
}
})
);

// 缓存 list 请求的数据
workbox.routing.registerRoute(
new RegExp('https://xxxxx'),
workbox.strategies.networkFirst({
cacheName: 'list'
})
);


workbox.precaching.precacheAndRoute(self.__precacheManifest || []);

然后打包部署就可以了。

扫码体验:

然后打开浏览器,找到【添加到主屏幕】(我用的 iOS,安卓应该也有类似的功能)

访问效果:

这只是一次 PWA 的简单尝试,实际项目中情况会比这个复杂得多,日后有机会再深入。

既然用到了 PWA,我又想到了 Vue 的 SSR,服务器端渲染我也没有接触过,后面有机会我再把项目改造一番。