如何使用 Next.js 构建渐进式 Web 应用 (PWA)
渐进式 Web 应用 (PWA) 结合了网页应用的广泛可访问性和原生移动应用的功能与用户体验。借助 Next.js,您可以创建跨平台无缝、类应用体验的 PWA,无需维护多个代码库或通过应用商店审核。
PWA 允许您:
- 即时部署更新,无需等待应用商店审核
- 使用单一代码库创建跨平台应用
- 提供类原生功能,如主屏幕安装和推送通知
使用 Next.js 创建 PWA
1. 创建 Web 应用清单
Next.js 通过 App Router 内置支持创建 Web 应用清单。您可以创建静态或动态清单文件:
例如,创建 app/manifest.ts
或 app/manifest.json
文件:
该文件应包含应用名称、图标及在用户设备上的显示方式等信息,这将允许用户将您的 PWA 安装到主屏幕,提供类原生应用的体验。
您可以使用 favicon 生成工具 创建不同尺寸的图标集,并将生成的文件放入 public/
文件夹。
2. 实现 Web 推送通知
Web 推送通知得到所有现代浏览器的支持,包括:
- iOS 16.4+(需安装至主屏幕)
- macOS 13 或更高版本的 Safari 16
- 基于 Chromium 的浏览器
- Firefox
这使得 PWA 成为原生应用的可行替代方案。值得注意的是,您无需离线支持即可触发安装提示。
Web 推送通知允许您在用户未主动使用应用时重新吸引他们。以下是在 Next.js 应用中实现的方法:
首先,在 app/page.tsx
中创建主页面组件。我们将分解为多个部分以便理解。首先添加所需的导入和工具函数(尚未实现的 Server Actions 可暂时忽略):
现在添加一个组件来管理推送通知的订阅、取消订阅和发送:
最后,创建一个组件来显示 iOS 设备的安装提示,仅在应用未安装时显示:
现在,让我们创建该文件调用的 Server Actions。
3. 实现 Server Actions
在 app/actions.ts
中创建新文件来处理订阅创建、删除和通知发送:
通知发送将由我们在第 5 步创建的服务工作者处理。
在生产环境中,您需要将订阅存储到数据库以实现服务器重启后的持久化,并管理多用户订阅。
4. 生成 VAPID 密钥
要使用 Web Push API,您需要生成 VAPID 密钥。最简单的方法是直接使用 web-push CLI:
首先全局安装 web-push:
运行以下命令生成 VAPID 密钥:
复制输出并将密钥粘贴到您的 .env
文件中:
5. 创建服务工作者
创建 public/sw.js
文件作为服务工作者:
该服务工作者支持自定义图片和通知。它处理传入的推送事件和通知点击:
- 使用
icon
和badge
属性可设置通知的自定义图标 - 调整
vibrate
模式可在支持的设备上创建自定义振动提醒 - 通过
data
属性可附加额外数据到通知
请务必全面测试您的服务工作者,确保其在不同设备和浏览器上表现符合预期。同时,请将 notificationclick
事件监听器中的 'https://your-website.com'
链接更新为您应用的实际 URL。
6. 添加到主屏幕
第 2 步中定义的 InstallPrompt
组件会向 iOS 设备显示一条消息,指导用户将应用安装到主屏幕。
要确保您的应用能够安装到移动设备主屏幕,必须满足以下条件:
- 有效的 Web 应用清单文件(已在第 1 步创建)
- 网站通过 HTTPS 提供服务
现代浏览器在满足这些条件时会自动向用户显示安装提示。您可以使用 beforeinstallprompt
提供自定义安装按钮,但我们不建议这样做,因为它不具备跨浏览器和跨平台兼容性(在 Safari iOS 上无效)。
7. 本地测试
要确保在本地能查看通知,请检查:
- 您正在通过 HTTPS 本地运行
- 测试时使用
next dev --experimental-https
命令
- 测试时使用
- 浏览器(Chrome、Safari、Firefox)已启用通知功能
- 本地测试时,接受使用通知的权限请求
- 确保浏览器未全局禁用通知
- 如果仍未看到通知,可尝试换用其他浏览器进行调试
8. 应用安全加固
安全性是任何 Web 应用的关键要素,对 PWA 尤为重要。Next.js 允许通过 next.config.js
文件配置安全标头,例如:
以下是各选项的详细说明:
- 全局标头(应用于所有路由):
X-Content-Type-Options: nosniff
:防止 MIME 类型嗅探,降低恶意文件上传风险X-Frame-Options: DENY
:通过禁止网站在 iframe 中嵌入,防止点击劫持攻击Referrer-Policy: strict-origin-when-cross-origin
:控制请求中包含的 Referrer 信息量,平衡安全性与功能性
- 服务工作者专用标头:
Content-Type: application/javascript; charset=utf-8
:确保服务工作者被正确解析为 JavaScriptCache-Control: no-cache, no-store, must-revalidate
:禁止缓存服务工作者,确保用户始终获取最新版本Content-Security-Policy: default-src 'self'; script-src 'self'
:为服务工作者实施严格的内容安全策略,仅允许同源脚本
详细了解如何通过 Next.js 定义内容安全策略 (Content Security Policy)。
后续步骤
- 探索 PWA 功能:PWA 可利用多种 Web API 提供高级功能。考虑探索后台同步 (background sync)、周期性后台同步 (periodic background sync) 或文件系统访问 API (File System Access API) 等功能来增强应用。有关 PWA 功能的最新信息,可参考 What PWA Can Do Today 等资源。
- 静态导出:如果您的应用不需要运行服务器,而是使用静态文件导出,可以更新 Next.js 配置启用此功能。详见 Next.js 静态导出文档。但需注意:您需要将服务器操作 (Server Actions) 改为调用外部 API,并将定义的标头移至代理服务器。
- 离线支持:要实现离线功能,可使用 Serwist 与 Next.js 集成。具体集成示例可查看其文档。注意:该插件当前需要 webpack 配置。
- 安全注意事项:确保服务工作者已正确加固,包括使用 HTTPS、验证推送消息来源以及实现适当的错误处理。
- 用户体验:考虑采用渐进增强 (progressive enhancement) 技术,确保即使用户浏览器不支持某些 PWA 功能,应用仍能良好运行。