This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
渐进式 Web 应用
编辑页面
了解如何为 Expo 网站添加渐进式 Web 应用支持。
渐进式 Web 应用(简称 PWA)是可以安装到用户设备上并可离线使用的网站。我们建议尽可能构建原生应用,因为它们具有最佳的离线支持,但对于桌面用户来说,PWA 也是一个很好的选择。
图标
Expo CLI 会根据 app.json 中的 web.favicon 字段自动生成 favicon.ico 文件。
{ "web": { "favicon": "./assets/favicon.png" } }
另外,你也可以在 public 目录中创建一个 favicon.ico 文件来手动指定图标。
清单文件
PWA 可以通过 manifest 文件进行配置,该文件描述应用的名称、图标和其他元数据。
1
在 public/manifest.json 中创建一个 PWA manifest:
{ "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.png 和 logo512.png 文件是在应用安装到用户设备上时会使用的图标。它们也应该添加到 public 目录中。
publicmanifest.jsonPWA 清单logo192.png192x192 图标logo512.png512x512 图标3
现在在你的 HTML 文件中链接 manifest。这里的方法取决于你网站的输出模式(在 app.json 中由 web.output 指示——默认值为 single)。
如果你使用的是单页应用,可以先在 public/index.html 中创建一个模板 HTML,然后在你的 HTML 文件中链接 manifest:
- npx expo customize public/index.html然后在 <head> 标签中添加 manifest:
<link rel="manifest" href="/manifest.json" />
如果你使用静态渲染或服务端渲染,HTML 入口可以在 src/app/+html.tsx 中动态创建。这里我们通过向 <head> 组件添加一个 <link> 标签来链接 manifest:
import { ScrollViewStyleReset } from 'expo-router/html'; import type { PropsWithChildren } from 'react'; // 此文件仅用于 Web,并用于在静态渲染期间为每个 // 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 manifest 文件。 */} <link rel="manifest" href="/manifest.json" /> {/* 禁用 Web 上的 body 滚动。这会让 ScrollView 组件的行为更接近原生端。 不过,在移动端 Web 上,保留 body 滚动通常也很有用。如果你想启用它,请删除这一行。 */} <ScrollViewStyleReset /> {/* 添加任何你希望在 Web 上全局可用的额外 <head> 元素... */} </head> <body>{children}</body> </html> ); }
Service Worker
Service worker 主要用于为网站添加离线支持。Google 的 Workbox 是为网站添加 service worker 的最佳方式。请参考 使用 Workbox CLI 的指南,并且其中凡是提到 “build script(构建脚本)” 的地方,都改为使用 npx expo export -p web。
警告 添加 service worker 时请务必小心,因为它们已知会在 Web 上引发意外行为。如果你不小心发布了一个激进缓存你网站的 service worker,用户将无法轻松请求更新。若想获得最佳的移动端离线体验,请使用 Expo 创建原生应用。与带有 service worker 的网站不同,原生应用可以通过应用商店更新来清除缓存体验。这类似于重置用户的原生浏览器(如果 service worker 足够激进,他们可能不得不这样做)。更多信息请参见 为什么 service worker 不是最佳选择。
例如,下面是一个设置 Workbox 的可能流程:
1
使用以下命令创建一个新项目:
- npm create expo -t tabs my-app- cd my-app2
现在在 HTML 文件中注册 service worker。这里的方法取决于你网站的输出模式(在 app.json 中由 web.output 指示——默认值为 single)。
接下来在根 index.html 中添加一个 service worker 注册脚本。
如果尚不存在,先在 public/index.html 中创建一个模板 HTML:
- npx expo customize public/index.html然后在 <head> 标签中创建 service worker 注册脚本:
<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 文件并添加 service worker 注册脚本:
import { ScrollViewStyleReset } from 'expo-router/html'; import type { PropsWithChildren } from 'react'; // 此文件仅用于 Web,并用于在静态渲染期间为每个 // 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" /> {/* 初始化 service worker。 */} <script dangerouslySetInnerHTML={{ __html: sw }} /> {/* 禁用 Web 上的 body 滚动。这会让 ScrollView 组件的行为更接近原生端。 不过,在移动端 Web 上,保留 body 滚动通常也很有用。如果你想启用它,请删除这一行。 */} <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
现在在运行向导之前先构建网站:
- npx expo export -p web4
运行向导命令,将 dist 设为应用的根目录,并对其他所有选项使用默认值:
- 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')? No5
最后,运行 npx workbox-cli generateSW workbox-config.js 以生成 service worker 配置。
从现在开始,你可以在 package.json 中添加一个构建脚本,以正确顺序运行这两个脚本:
{ "scripts": { "build:web": "expo export -p web && npx workbox-cli generateSW workbox-config.js" } }
6
如果你托管了你的网站并使用 Chrome 访问,可以在 Chrome DevTools 中通过进入 Application > Service Workers 来检查 service worker。