PWA之vite-plygin-pwa

720 阅读4分钟

偶然间接触到了pwa相关的技术,简单的技术选型之后决定使用vite社区提供的vite-plugin-pwa,相对直接用workbox来说更加的简单明了(基于此进行的二次封装)。

什么是PWA

渐进式 web 应用(PWA)通过结合 Web 和移动应用的特点,为用户带来更加流畅和快速的体验。且 PWA 支持离线访问能力(访问静态资源本地缓存),极大提高了用户交互的流畅性,降低非必要的网络依赖。尤其适合在手机端创建。

当前是基于 Vite 的基础上使用 vite-plugin-pwa 实现 A2HS (Add To Home Screen)和 workbox 离线缓存功能。

基本使用

install

yarn add vite-plugin-pwa

引入(dev.config.ts) 直接放入vite.config.ts都行

import { VitePWA } from 'vite-plugin-pwa'
import { defineConfig } from 'vite'

// 缓存分配逻辑
const getCache = ({ name, pattern }: any) => ({
	urlPattern: pattern,
	handler: 'CacheFirst' as const,
	options: {
		cacheName: name,
		expiration: {
			maxEntries: 500,
			maxAgeSeconds: 60 * 60 * 24 * 365 * 2 // 2 years
		},
		cacheableResponse: {
			statuses: [200]
		}
	}
})


export default defineConfig(({ command }) => {
	const isServe = command === 'serve'
	return {
		build: {
			sourcemap: true
		},
		plugins: [
			VitePWA({
				registerType: 'autoUpdate', // 注册类型配置
				devOptions: {
					enabled: true // 开发选项配置,启用插件
					//type: 'module'
				},
				manifest: {
					name: 'App', // 请求弹窗内name显示
					short_name: 'v-pwa', // 正在添加[name]... 和 桌面显示name
					description: '一个Vite PWA测试APP',
					theme_color: '#fafafa',
					icons: [
						{
							src: '/face_192.png',
							sizes: '192x192',
							type: 'image/png'
						},
						{
							src: '/face_512.png',
							sizes: '512x512',
							type: 'image/png'
						}
					],
					shortcuts: [
						{
							name: 'docs', // 快捷方式名称
							description: 'docs', // 快捷方式描述
							url: '/docs/docsIndex', // 快捷方式链接地址
						}
					]
				},
				workbox: {
					globPatterns: ['**/*.{js,css,html,ico,png,jpg,svg}'], //缓存相关静态资源
					runtimeCaching: [
						// 配置自定义运行时缓存
						//getCache({
						//	pattern: /^https:\/\/enjoytoday.cn\/wp-uploads/,
						//	name: 'local-upload'
						//}),
						getCache({
							pattern: /^https:\/\/baidu.cn/,
							name: 'webapp'
						})
					]
				}
			})
		]
	}
})

使用

  • 到这里其实就已经可以在chrome浏览器的地址栏右侧上看到一个可以打开的icon标识了

image.png

但这个仅限于是手动主动的打开,如果想要从UI页面引导用户打开的话还需要做一些处理(移动端必须)

  1. 监听当前浏览器是否支持A2HS,支持则会回调返回event,我们需要对此做一个保存,方便后期调用请求弹窗
window.addEventListener('beforeinstallprompt', (e) => {
        // 取消该事件 
	e.preventDefault()
        // 保存event
	window.deferredPrompt = e
})
  1. 保存之后就可以根据需求去引导用户打开是否安装应用的弹窗
// 若浏览器支持,则这里会出发安装操作
const handleGoOpenWin = () => {
	// 是否支持此事件(chrome)
	if ('BeforeInstallPromptEvent' in window) {
		console.log('Chrome-style PWA install experience supported!')
	}
	if ('standalone' in navigator) {
		// only available on iOS - but also on alternative browsers on iOS without Add-to-Homescreen support
		console.log('iOS Safari-style PWA Add-to-Homescreen maybe supported!')
	}

	try {
		// 拉起请求弹窗
		window.deferredPrompt.prompt()
		window.deferredPrompt.userChoice.then((choiceResult) => {
			// 点击同意,进行安装
			if (choiceResult.outcome === 'accepted') {
				console.log('acceptttttt!!!!!')
				window.localStorage.setItem('isAcceptPWA', '1')
				window.deferredPrompt = null
			} else {
				console.log('User dismissed the A2HS prompt')
			}
		})
	} catch (e) {
		console.log(e, 'eee')
	}
}

事件按需求进行任意触发。

  • 请求弹窗 image.png

注意点(坑)

  1. 在config中配置manifest时,在icons内,设置图标必须设置192及以上大小的图标,且必须跟图标实际大小一致,最好设置一个192192,一个512512的
  2. 跟上一点一个位置,icon内设置图标时最好选择png格式,且类型必须和type一致(都是血与泪..)

image.png

  1. config的manifest中,theme_color值必须与入口文件(index.html)中的meta的theme-color一致

image.png

image.png

目前发现的一些问题

  1. 安卓有时候添加会非常的耗时(慢)(国内环境缘故)
  2. 安装流程必须是用户在当前页面有交互之后才可以进行,否则无效

扩展

自定义应用展示内容

有些需求是想要生成的应用内地址改动,不止显示原有的链接内容(而且地址栏参数也会消失)

这里就需要使用iframe占据全部的视图,然后根据是否accept来判断iframe是否进行展示,从而进行对应的操作。

image.png

自定义应用打开后的路径(可带参数)

前置要求

  • scope内需要标明可使用路径(可以是根)
  • start_url必须是在scope限定的范围内,否则无效
  • id跟syart_url一致

image.png

  • 必须是history路由,hash不行(无法得知#之后的变化)
  • 线上内容得在安全域名下(https)才可以正常显示 image.png
  • 接口返回内容必须为纯JSON内容

动态写入start_url(create)

image.png

主要就是根据需求拼接接口内容,随后直接插入<link rel='manifest' src='接口'><link/>

参考文章