Hexo版本:4.2.1

Butterfly版本:3.0.0 RC1

了解

使用前先了解一下什么是PWA:

PWA(Progressive Web App)是一种理念,使用多种技术来增强 web app 的功能,可以让网站的体验变得更好,能够模拟一些原生功能,比如通知推送。在移动端利用标准化框架,让网页应用呈现和原生应用相似的体验。

PWA 不能包含原生OS相关代码。PWA 仍然是网站,只是在缓存、通知、后台功能等方面表现更好。Electron 程序相当于包裹OS原生启动器(Launcher)的网站,未来,许多Electron 程序可能转化为 PWA。

启用

在 Hexo 主题 Butterfly 3.0.0 RC1 版本中,作者已经集成了 PWA 特性,只是需要手动开启和设置一些参数。

安装插件

npm install hexo-offline --save 或者 yarn add hexo-offline

修改站点配置文件

修改 _config.yml 文件,增加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
## offline config passed to sw-precache.
offline:
maximumFileSizeToCacheInBytes: 10485760 ## 缓存的最大文件大小,以字节为单位
staticFileGlobs:
- public/**/*.{js,html,css,png,jpg,gif,svg,webp,eot,ttf,woff,woff2}
## 静态文件合集,如果你的站点使用了例如webp格式的文件,请将文件类型添加进去。
stripPrefix: public
verbose: true
runtimeCaching:
## CDNs - should be cacheFirst, since they should be used specific versions so should not change
- urlPattern: /* ## 如果你需要加载CDN资源,请配置该选项,如果没有,可以不配置。
handler: cacheFirst
options:
origin: your_websie_url ## 可替换成你的 url

更多内容请查看 hexo-offline 的官方文档。

配置主题设置

修改 butterfly.yml 文件:

1
2
3
4
5
6
7
8
pwa:
enable: true
manifest: /img/pwa/manifest.json
theme_color: "#fff"
apple_touch_icon: /img/pwa/apple-touch-icon.png
favicon_32_32: /img/pwa/32.png
favicon_16_16: /img/pwa/16.png
mask_icon: /img/pwa/safari-pinned-tab.svg

这里的图标文件需要自己手动添加

配置 JSON 文件

source/img/pwa/ 目录中创建 manifest.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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
"name": "string", //应用全称
"short_name": "Junzhou", //应用简称
"theme_color": "#49b1f5", //匹配浏览器的地址栏颜色
"background_color": "#49b1f5",//加载应用时的背景色
"display": "standalone",//首选显示模式 其他选项有:fullscreen,minimal-ui,browser
"scope": "/",
"start_url": "/",
"icons": [ //该数组指定icons图标参数,用来时适配不同设备(需为png,至少包含一个192px*192px的图标)
{
"src": "pwaicons/36.png", //图标文件的目录,这里的根目录是source/img/pwa/
"sizes": "36x36", //在source/img/pwa下新建文件夹pwaicons,把下面的这几个图标文件放进去
"type": "image/png"
},
{
"src": "pwaicons/48.png",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "pwaicons/72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "pwaicons/96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "pwaicons/144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "pwaicons/192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "pwaicons/512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"splash_pages": null //配置自定义启动动画。
}

注意,JSON 文件是不建议有注释的可能会报错,建议删除注释

你也可以通过 Web App Manifest 快速创建 manifest.json( Web App Manifest 要求至少包含一个 512*512 像素的图标)

可以通过 Chrome 插件 Lighthouse 检查 PWA 配置是否生效以及配置是否正确:

  • 打开博客页面
  • 启动 Lighthouse 插件 ( Lighthouse 插件要求至少包含一个 512*512 像素的图标)

关于 PWA(渐进式增强 Web 应用)的更多内容请参阅 Google Tools for Web Developers

警告:如果要执行下面的操作,请卸载 hexo-offline 插件,并删除在 _config.yml 中的配置

另一种方法

需要注意的是,manifest.json 文件和 PWA 配置和上面一模一样,只是不需要 offline 配置和插件而已

开启设置和配置 manifest.json

安装插件

1
npm install workbox-build gulp --save-dev

创建 gulpfile.js 文件

在博客根目录,创建一个 gulpfile.js 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const gulp = require("gulp");
const workbox = require("workbox-build");

gulp.task('generate-service-worker', () => {
return workbox.injectManifest({
swSrc: './sw-template.js',
swDest: './public/sw.js',
globDirectory: './public',
globPatterns: [
"**/*.{html,css,js,json,woff2}"
],
modifyURLPrefix: {
"": "./"
}
});
});

gulp.task("build", gulp.series("generate-service-worker"));

创建 sw-template.js 文件

在博客的根目录里创建一个 sw-template.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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
const workboxVersion = '5.1.3';

importScripts(`https://storage.googleapis.com/workbox-cdn/releases/${workboxVersion}/workbox-sw.js`);

workbox.core.setCacheNameDetails({
prefix: "your name"
});

workbox.core.skipWaiting();

workbox.core.clientsClaim();

workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);

workbox.precaching.cleanupOutdatedCaches();

// Images
workbox.routing.registerRoute(
/\.(?:png|jpg|jpeg|gif|bmp|webp|svg|ico)$/,
new workbox.strategies.CacheFirst({
cacheName: "images",
plugins: [
new workbox.expiration.ExpirationPlugin({
maxEntries: 1000,
maxAgeSeconds: 60 * 60 * 24 * 30
}),
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200]
})
]
})
);

// Fonts
workbox.routing.registerRoute(
/\.(?:eot|ttf|woff|woff2)$/,
new workbox.strategies.CacheFirst({
cacheName: "fonts",
plugins: [
new workbox.expiration.ExpirationPlugin({
maxEntries: 1000,
maxAgeSeconds: 60 * 60 * 24 * 30
}),
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200]
})
]
})
);

// Google Fonts
workbox.routing.registerRoute(
/^https:\/\/fonts\.googleapis\.com/,
new workbox.strategies.StaleWhileRevalidate({
cacheName: "google-fonts-stylesheets"
})
);
workbox.routing.registerRoute(
/^https:\/\/fonts\.gstatic\.com/,
new workbox.strategies.CacheFirst({
cacheName: 'google-fonts-webfonts',
plugins: [
new workbox.expiration.ExpirationPlugin({
maxEntries: 1000,
maxAgeSeconds: 60 * 60 * 24 * 30
}),
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200]
})
]
})
);

// Static Libraries
workbox.routing.registerRoute(
/^https:\/\/cdn\.jsdelivr\.net/,
new workbox.strategies.CacheFirst({
cacheName: "static-libs",
plugins: [
new workbox.expiration.ExpirationPlugin({
maxEntries: 1000,
maxAgeSeconds: 60 * 60 * 24 * 30
}),
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200]
})
]
})
);

workbox.googleAnalytics.initialize();

prefix 修改为你博客的名字(英文),如果你想用其它缓存策略,请自行查看相关文档

添加 js 文件进主题

配置 butterfly.yml ,添加需要的 css 和 js 文件

1
2
3
4
5
inject:
head:
- '<style type="text/css">.app-refresh{position:fixed;top:-2.2rem;left:0;right:0;z-index:99999;padding:0 1rem;font-size:15px;height:2.2rem;transition:all .3s ease}.app-refresh-wrap{display:flex;color:#fff;height:100%;align-items:center;justify-content:center}.app-refresh-wrap a{color:#fff;text-decoration:underline;cursor:pointer}</style>'
bottom:
- '<div class="app-refresh" id="app-refresh"> <div class="app-refresh-wrap"> <label>✨ 网站已更新最新版本 👉</label> <a href="javascript:void(0)" onclick="location.reload()">点击刷新</a> </div></div><script>function showNotification(){if(GLOBAL_CONFIG.Snackbar){var t="light"===document.documentElement.getAttribute("data-theme")?GLOBAL_CONFIG.Snackbar.bgLight:GLOBAL_CONFIG.Snackbar.bgDark,e=GLOBAL_CONFIG.Snackbar.position;Snackbar.show({text:"已更新最新版本",backgroundColor:t,duration:5e5,pos:e,actionText:"点击刷新",actionTextColor:"#fff",onActionClick:function(t){location.reload()}})}else{var o=`top: 0; background: ${"light"===document.documentElement.getAttribute("data-theme")?"#49b1f5":"#1f1f1f"};`;document.getElementById("app-refresh").style.cssText=o}}"serviceWorker"in navigator&&(navigator.serviceWorker.controller&&navigator.serviceWorker.addEventListener("controllerchange",function(){showNotification()}),window.addEventListener("load",function(){navigator.serviceWorker.register("/sw.js")}));</script>'

运行

在你运行 hexo g 后,记得要运行 gulp build 这样才会生效

如果安装完插件发现 gulp 命令无法使用的话,请尝试全局安装:npm install --global gulp-cli

作者: Jerry
連結: https://demo.jerryc.me/posts/ceeb73f/#PWA
來源: Butterfly
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。