当项目需要在无网络的情况下也能正常访问并使用, 这时候转换成 PWA 应用安装到本地最适合不过, 恰巧有个项目部署在 github page 上, 恰巧 PWA 要求 https, 于是来实践一下, 首先浏览器判断网页是否为 PWA, 即是否支持安装到本地是需要满足一定条件的, 具体参考 https://vite-pwa-org.netlify.app/guide/pwa-minimal-requirements.html , 大体要做三部分工作:
-
manifest: JSON 文件, 里面包含浏览器如何识别网页的必要信息, 具体参考 https://web.dev/learn/pwa/web-app-manifest
-
icons: 作为应用安装到本地后显示的图标, 而且要求多种格式大小, 以便兼容不同的设备
-
Service Worker: 相当于应用和云端服务器之间的代理服务器, 可以拦截资源的请求, 对资源进行缓存
即使知道这三点, 真实际手动配置起来还挺繁琐的, 恰巧我的项目是 vite 项目, 有 PWA 相关的成熟插件, 配置成 PWA 方便很多, 先安装插件
安装 vite-plugin-pwa 插件
pnpm add -D vite-plugin-pwa配置插件
import { VitePWA } from 'vite-plugin-pwa'
export default defineConfig({
plugins: [
VitePWA({
registerType: "autoUpdate",
manifest: {
id: "",
name: "",
short_name: "",
theme_color: "#ffffff",
icons: [],
},
})
]
})现在打包后, index.html 就会自动引入一个 manifest 文件, 里面包含了一些最简单的配置, 按理说, 浏览器若识别网页是 PWA 会在地址栏弹出一个安装按钮, 但现在没有, 因为还没有配置 icons, 因为 icon 需要多种格式大小, 手动处理起来不方便, 可以使用 @vite-pwa/assets-generator 命令行工具快速生成需要的多种大小图标
https://vite-pwa-org.netlify.app/assets-generator/#example-using-minimal-preset https://maskable.app/editor
pnpm add -D @vite-pwa/assets-generatornpx pwa-assets-generator --preset minimal-2023 public/logo.svg执行后会看到 public 目录下多处个 png 文件, 在命令行还能看到以下输出:
<link rel="icon" href="/favicon.ico" sizes="48x48">
<link rel="icon" href="/vite.svg" sizes="any" type="image/svg+xml">
<link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png">
{
"icons": [
{
"src": "pwa-64x64.png",
"sizes": "64x64",
"type": "image/png"
},
{
"src": "pwa-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "pwa-512x512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "maskable-icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}
前一个输出复制到 index.html 的 head 中, 后一个输出复制 vite 配置中, 这样重新打包后, 完整的 PWA 应用就完成了
import { VitePWA } from 'vite-plugin-pwa'
export default defineConfig({
plugins: [
VitePWA({
registerType: "autoUpdate",
manifest: {
id: "",
name: "",
short_name: "",
theme_color: "#ffffff",
icons: [
{
src: "pwa-64x64.png",
sizes: "64x64",
type: "image/png",
},
{
src: "pwa-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "pwa-512x512.png",
sizes: "512x512",
type: "image/png",
purpose: "any",
},
{
src: "maskable-icon-512x512.png",
sizes: "512x512",
type: "image/png",
purpose: "maskable",
},
],
},
})
]
})<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" sizes="48x48" />
<link rel="icon" href="/logo.svg" sizes="any" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png" />
<title>demo</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>生成启动页
https://vite-pwa-org.netlify.app/assets-generator/cli.html#ios-ipad-splash-screens
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" sizes="48x48" />
<link rel="icon" href="/logo.svg" sizes="any" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon-180x180.png" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<link
rel="apple-touch-startup-image"
media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"
href="/apple-splash-portrait-1125x2436.png"
/>
<link
rel="apple-touch-startup-image"
media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)"
href="/apple-splash-landscape-2436x1125.png"
/>
<title>demo</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>https://progressier.com/pwa-icons-and-ios-splash-screen-generator https://developer.apple.com/design/human-interface-guidelines/layout