服务器渲染
编辑页面
了解如何使用服务器端渲染(SSR)在请求时动态渲染 Expo Router 路由。
For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.
服务端渲染(SSR)会在每次请求时动态生成 HTML,而 静态渲染 则是在构建时预渲染 HTML。本指南将引导你为 Expo Router 应用启用服务器渲染。
信息 使用服务端渲染时,数据加载器 会在服务器上针对每次请求执行,其结果会嵌入到 HTML 响应中。
设置
1
在项目的应用配置中启用服务器渲染:
{ "expo": { %%placeholder-start%%... %%placeholder-end%% "web": { "output": "server" }, "plugins": [ [ "expo-router", { "unstable_useServerRendering": true } ] ] } }
2
启动开发服务器:
- npx expo start生产环境
要为生产环境导出你的应用,请运行导出命令:
- npx expo export --platform web这会创建一个包含服务器渲染应用的 dist 目录。与静态渲染不同,不会预先生成 HTML 文件。相反,输出会包含如下所示的类似目录结构:
distclient_expostaticjswebentry-[hash].jscss[name]-[hash].cssserver_exporoutes.jsonserverrender.js上面的输出在 dist 目录中包含以下目录:
- client 目录:包含用于客户端 hydration 的 JavaScript 和 CSS bundles
- server 目录:包含路由清单和服务器渲染模块
你可以通过运行以下命令并在浏览器中打开链接的 URL 来本地测试生产构建:
- npx expo serve上述命令会启动一个本地服务器,在每次请求时渲染页面,模拟生产环境。
动态路由
使用服务器渲染时,动态路由会即时渲染,因此不需要 generateStaticParams 导出,并且应当移除。如果你的路由文件导出了 generateStaticParams,这些路由将改为动态处理。路由会在请求时使用 URL 中的实际参数进行渲染。
import { Text } from 'react-native'; import { useLocalSearchParams } from 'expo-router'; export default function Page() { const { id } = useLocalSearchParams(); return <Text>帖子 {id}</Text>; }
在上面的示例中,当应用用户访问 /blog/my-post 时,该页面会在服务器上渲染,且 id 被设置为 "my-post"。
根 HTML
你可以通过创建 src/app/+html.tsx 文件来自定义根 HTML 文档。此组件会包裹所有路由,并且只在服务器上运行。
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" /> {/* 禁用 web 上的 body 滚动。这会让 ScrollView 组件的行为更接近它们在原生平台上的表现。 不过,对于移动端 web 来说,body 滚动通常也很有用。如果你想启用它,请移除这一行。 */} <ScrollViewStyleReset /> {/* 添加任何你希望在 web 上全局可用的额外 <head> 元素... */} </head> <body>{children}</body> </html> ); }
+html.tsx 文件仅由服务器渲染器使用,客户端代码永远不会使用它。这意味着:
- 它会在服务器渲染期间由
expo-server运行 - 它不会在客户端重新 hydration,因此不应使用 React hooks
- 你不能在
+html.tsx中导入全局 CSS(请使用根布局来设置样式) - 你不能在
+html.tsx中调用window或document之类的浏览器 API
所有 +html.tsx 组件都应在其 JSX 内容中渲染它们接收到的 children 属性。
元标签
使用 expo-router 的 <Head /> 组件为你的页面添加 meta 标签:
import Head from 'expo-router/head'; import { Text } from 'react-native'; export default function Page() { return ( <> <Head> <title>关于我们</title> <meta name="description" content="了解更多关于我们公司的信息。" /> </Head> <Text>关于页面内容</Text> </> ); }
在服务器端渲染期间,<Head> 元素会被提取并包含在初始 HTML 响应中,从而修改发送给客户端的 <head> 元素,并提升搜索引擎优化(SEO)。
部署
服务器端渲染要求有一个运行时服务器来在每次请求时渲染页面。使用服务器端渲染的 Expo 应用不能部署到 GitHub Pages 之类的静态托管服务上。
支持的平台
| 平台 | 适配器 |
|---|---|
| EAS Hosting | 内置 |
| Node.js/Express | expo-server/adapter/express |
| Cloudflare Workers | expo-server/adapter/workerd |
| Vercel Edge Functions | expo-server/adapter/vercel |
| Netlify Edge Functions | expo-server/adapter/netlify |
| Bun | expo-server/adapter/bun |
示例:使用 EAS Hosting 部署
EAS Hosting 开箱即支持服务器渲染。导出你的应用并使用以下命令部署:
- npx expo export --platform web- npx eas-cli@latest hosting:deploy dist与静态渲染的比较
| 功能 | 静态渲染 | 服务器渲染 | |
|---|---|---|---|
| HTML 生成 | 构建时 | 请求时 | |
| 配置 | web.output: 'static' | web.output: 'server' | |
| 动态路由 | 需要 generateStaticParams | 自动工作 | |
| 需要服务器 | 否 | 是 | |
| 首字节时间 | 最快(缓存) | 更慢(每次请求渲染) | |
| 托管 | 任何静态主机 | 需要服务器运行时 |
常见问题
我可以在服务器渲染中使用数据加载器吗?
可以。服务器渲染可与数据加载器配合使用,在渲染之前先在服务器上获取数据。
服务器渲染支持 API 路由吗?
可以。API 路由 与渲染模式相互独立。它们始终在服务器上执行。