VuePress 教程(?):用 VuePress 搭建 PWA
Posted: 11.18.2019
介绍
讲道理这其实应该是 VuePress 教程比较靠后的一个部分。
不过我其实暂时还没有想要写 VuePress 的教程(但我感觉其实挺必要的,因为我觉得目前的教程都不咋样)。
所以标题会有一个 ?。等我开始写 VuePress 教程后,再把 ? 换成数字。
pwa 本身需要讲一下,不算简单,不过 VuePress 的 pwa 都帮你差不多写好了,所以很简单。
其实只要跟着 VuePress 的文档走就行了,但有些东西需要额外提一下。
效果
先给大家看一下最终达成的效果:

manifest.json
首先,pwa 是需要一个 manifest.json 来处理各种 native 的表现的。
学过 pwa 的人肯定会,但如果对 pwa 不太熟悉的话,还是需要看一下的。
{
// name 是你打开 app 的时候,底下跳出的 name
"name": "Lynch 的博客",
// background_color 就是打开 app 的时候,背景颜色
"background_color": "white",
// short_name 就是你 app 图标下的名字
"short_name": "Lynch",
// 语言,zh-CN 就是中文
"lang": "zh-CN",
// start_url 就是当你点击 app 图标后,打开的页面
"start_url": "/index.html",
// standalone 就是以独立 app 的样式打开,不展示浏览器
"display": "standalone",
/**
* theme_color 管的是页面以外的 theme,比如地址栏
* 和 meta 标签里的 theme-color 效果一样
* 但是会被 meta 标签里的 theme-color 所覆盖
* 并且如果是 standalone 的话,用不到这个
*/
"theme_color": "white",
/**
* orientation 简单来说就是横屏还是竖屏
* 但其实配置的选项蛮多的,一般情况下就用 portrait-primary
*/
"orientation": "portrait-primary",
/**
* icons 就是你原生 app 的图标,因为不同的系统需要不同的图标大小
* 所以这里需要提供一大堆图标
*/
"icons": [
{
"src": "/icons/lynch-icon-128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "/icons/lynch-icon-144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "/icons/lynch-icon-152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "/icons/lynch-icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/lynch-icon-256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src": "/icons/lynch-icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
这个 manifest.json 就放在 public 里就行了。
head
安装就不说了,直接看文档:@vuepress/plugin-pwa
接下来看一下 head,因为我们知道,为了支持 pwa,我们需要设置一些特殊的 head。
module.exports = {
head: [
// 这个其实就是 favicon,如果已经设了 favicon 就可以不用管
['link', { rel: 'icon', href: '/logo.png' }],
// 这个指向上面的 manifest.json
['link', { rel: 'manifest', href: '/manifest.json' }],
// 这个刚才说了,如果在这里定义了,会覆盖 manifest 文件里的 theme_color
['meta', { name: 'theme-color', content: '#3eaf7c' }],
/**
* ios 需要的 head,content = yes 才会是全屏模式
* 在 manifest 里设置 standalone 对于 ios 是无效的
*/
['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }],
/**
* ios 需要的 head,只有在设置了上面那个 meta 的情况下才有效
* 指定了状态栏的颜色(就是手机最上方显示时间,wifi信号的那一行)
*/
['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'default' }],
// ios 需要的 head,指定了添加到桌面时的图标
['link', { rel: 'apple-touch-icon', href: '/icons/apple-touch-icon-152x152.png' }],
// ios 需要的 head,简单来说就是 favicon
['link', { rel: 'mask-icon', href: '/icons/safari-pinned-tab.svg', color: '#3eaf7c' }],
// windows 8 需要的 head,简单来说就是 favicon
['meta', { name: 'msapplication-TileImage', content: '/icons/msapplication-icon-144x144.png' }],
// windows 8 需要的 head,简单来说就是图标背后格子的颜色
['meta', { name: 'msapplication-TileColor', content: '#000000' }]
],
plugins: ['@vuepress/pwa', {
// 开启 service worker
serviceWorker: true,
// 如果有 update 的话,是否展示弹窗
updatePopup: true
}],
}
service worker
在生产环境下编译后,我们就能看见 server-worker.js 这个文件。
VuePress 的 service worker 是通过 workbox 来生成的。
workbox 这里就不详细说了,简单来说就是 Google 的一个处理 service worker 的工具。
如果你去 service-worker.js 这个文件里查看,你是看不见一般的 service worker 需要的 install、activate、fetch 这些事件的,那是因为 workbox 已经把这些事情处理好了。也就是说我们不需要去关心怎么注册安装 service worker 这些东西,只需要直接用就行了。
修改弹窗
这个时候,如果我们更新的内容,我们页面的右下角会出现一个这样的弹窗:

安卓设备也是一样,iOS 则是没有这个弹窗(iOS 对 pwa 的支持大家有目共睹)。
但是这么一个弹窗看上去好像不是特别好看啊。作为一个前端,自然得改得好看一点。
所以根据 VuePress 文档的指引,我们去 .vuepress/components 里新建我们自己的组件。
注意,如下的操作对我无效!我目前还不知道正确修改弹窗的方式!
我自己的组件长这样:
<template>
<SWUpdatePopup>
<div v-slot="{ enabled, reload, message, buttonText }" class="my-sw-update-popup">
傻屌作者又更新啦!!!
<br />
<v-btn @click="reload">刷新</v-btn>
</div>
</SWUpdatePopup>
</template>
<script>
import SWUpdatePopup from "@vuepress/plugin-pwa/lib/SWUpdatePopup.vue";
export default {
components: { SWUpdatePopup }
};
</script>
<style>
@keyframes drop {
0% {
top: -20px;
oapcity: 0;
}
100% {
top: 20px;
opacity: 1;
}
}
.my-sw-update-popup {
text-align: right;
position: fixed;
top: 20px;
right: 20px;
background-color: #fff;
font-size: 20px;
padding: 10px;
border: 5px solid mediumpurple;
animation: drop 2s cubic-bezier(0.075, 0.82, 0.165, 1) forwards;
}
.my-sw-update-popup button {
border: 1px solid #fefefe;
}
</style>
然后去 config 里指定我们自己的组件作为弹窗:
module.exports = {
plugins: {
'@vuepress/pwa': {
serviceWorker: true,
+ popupComponent: 'MySWUpdatePopup',
updatePopup: true
}
}
}
总结
那么我们基本上已经完成了 VuePress 站点 pwa 的构建。
如果需要像手机一样,有消息的推送,而不是这样的弹窗,那么是需要服务器的。
如果真的想要这么做(虽然我觉得没必要),那么大家可以建一个 node 服务器,然后自己去搞。