渐进式网页应用

编辑

了解如何为 Expo 网站添加渐进式网页应用支持。


渐进式网页应用(简称 PWA)是可以安装在用户设备上并离线使用的网站。我们建议尽可能构建原生应用,因为它们具有最佳的离线支持,但 PWA 对桌面用户来说是一个很好的选择。

网站图标

Expo CLI 会根据 app.json 中的 web.favicon 字段自动生成 favicon.ico 文件。

{ "web": { "favicon": "./assets/favicon.png" } }

或者,您可以在 public 目录中创建一个 favicon.ico 文件以手动指定图标。

清单文件

PWA 可以通过 清单文件 进行配置,该文件描述了应用的名称、图标和其他元数据。

1

public/manifest.json 中创建一个 PWA 清单:

{ "short_name": "Expo App", "name": "Expo Router Sample", "icons": [ { "src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon" }, { "src": "logo192.png", "type": "image/png", "sizes": "192x192" }, { "src": "logo512.png", "type": "image/png", "sizes": "512x512" } ], "start_url": ".", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff" }

2

文件 logo192.pnglogo512.png 是在用户设备上安装应用时使用的图标。这些文件也应添加到 public 目录中。

public
manifest.jsonPWA 清单
logo192.png192x192 图标
logo512.png512x512 图标

3

现在在您的 HTML 文件中链接清单。方法取决于您网站的输出模式(在 app.json 中的 web.output 指定,默认为 single)。

如果您正在使用单页面应用,可以通过在 public/index.html 中创建一个模板 HTML 来链接清单:

Terminal
npx expo customize public/index.html

然后将清单添加到 <head> 标签中:

<link rel="manifest" href="/manifest.json" />

如果您正在使用静态或服务器渲染,可以在 app/+html.tsx 中动态创建 HTML 入口。在这里,我们将通过将 <link> 标签添加到 <head> 组件来链接清单:

app/+html.tsx
import { ScrollViewStyleReset } from 'expo-router/html'; import type { PropsWithChildren } from 'react'; // 此文件仅限于 Web,用于配置每个 // 网页在静态渲染期间的根 HTML。 // 此函数的内容仅在 Node.js 环境中运行, // 并且无法访问 DOM 或浏览器 API。 export default function Root({ children }: PropsWithChildren) { return ( <html lang="en"> <head> <meta charSet="utf-8" /> <meta httpEquiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> {/* 链接 PWA 清单文件。 */} <link rel="manifest" href="/manifest.json" /> {/* 在 Web 上禁用主体滚动。这使得 ScrollView 组件的工作方式更接近于原生。 然而,主体滚动在移动 Web 上通常是不错的选择。如果您想启用它,请删除此行。 */} <ScrollViewStyleReset /> {/* 添加任何您希望在 Web 上全局可用的额外 <head> 元素... */} </head> <body>{children}</body> </html> ); }

服务工作者

服务工作者主要用于为网站添加离线支持。谷歌的 Workbox 是将服务工作者添加到网站的最佳方式。请遵循 使用 Workbox CLI 的指南,在提到“构建脚本”的地方,将其替换为 npx expo export -p web

添加服务工作者时请小心,因为它们已知会导致 Web 上的意外行为。如果您意外发布了一个强力缓存您网站的服务工作者,用户将无法轻松请求更新。为了获得最佳的离线移动体验,请使用 Expo 创建原生应用。与有服务工作者的网站不同,原生应用可以通过应用商店进行更新,以清除缓存的体验。这类似于重置用户的原生浏览器(如果服务工作者足够强力,他们可能不得不这样做)。有关更多信息,请参见 为什么服务工作者是次优的

例如,以下是设置 Workbox 的可能流程:

1

使用以下命令创建一个新项目:

Terminal
npm create expo -t tabs my-app

cd my-app

2

现在在 HTML 文件中注册服务工作者。方法取决于您网站的输出模式(在 app.json 中的 web.output 指定,默认为 single)。

接下来,在根 index.html 中添加服务工作者注册脚本。

如果尚未存在,则首先在 public/index.html 中创建一个模板 HTML:

Terminal
npx expo customize public/index.html

然后在 <head> 标签中创建服务工作者注册脚本:

<script> if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker .register('/sw.js') .then(registration => { console.log('Service Worker registered with scope:', registration.scope); }) .catch(error => { console.error('Service Worker registration failed:', error); }); }); } </script>

接下来,为应用创建一个根 HTML 文件,并添加服务工作者注册脚本:

app/+html.tsx
import { ScrollViewStyleReset } from 'expo-router/html'; import type { PropsWithChildren } from 'react'; // 此文件仅限于 Web,用于配置每个 // 网页在静态渲染期间的根 HTML。 // 此函数的内容仅在 Node.js 环境中运行, // 并且无法访问 DOM 或浏览器 API。 export default function Root({ children }: PropsWithChildren) { return ( <html lang="en"> <head> <meta charSet="utf-8" /> <meta httpEquiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> {/* 启动服务工作者。 */} <script dangerouslySetInnerHTML={{ __html: sw }} /> {/* 在 Web 上禁用主体滚动。这使得 ScrollView 组件的工作方式更接近于原生。 然而,主体滚动在移动 Web 上通常是不错的选择。如果您想启用它,请删除此行。 */} <ScrollViewStyleReset /> {/* 添加任何您希望在 Web 上全局可用的额外 <head> 元素... */} </head> <body>{children}</body> </html> ); } const sw = ` if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js').then(registration => { console.log('Service Worker registered with scope:', registration.scope); }).catch(error => { console.error('Service Worker registration failed:', error); }); }); } `;

3

现在在运行向导之前构建网站:

Terminal
npx expo export -p web

4

运行向导命令,选择 dist 作为应用的根目录,并选择其他所有项的默认值:

Terminal
npx workbox-cli wizard

? What is the root of your web app (that is which directory do you deploy)? dist/? Which file types would you like to precache? js, html, ttf, ico, json? Where would you like your service worker file to be saved? dist/sw.js? Where would you like to save these configuration options? workbox-config.js? Does your web app manifest include search parameter(s) in the 'start_url', other than 'utm_' or 'fbclid' (like '?source=pwa')? No

5

最后,运行 npx workbox-cli generateSW workbox-config.js 以生成服务工作者配置。

今后,您可以在 package.json 中添加构建脚本,以按正确顺序运行这两个脚本:

package.json
{ "scripts": { "build:web": "expo export -p web && npx workbox-cli generateSW workbox-config.js" } }

6

如果您托管网站并使用 Chrome 访问,可以通过前往 Chrome DevTools 中的 Application > Service Workers 来检查服务工作者。