服务器渲染

编辑页面

了解如何使用服务器端渲染(SSR)在请求时动态渲染 Expo Router 路由。


For the complete documentation index, see llms.txt. Use this Use this file to discover all available pages.

重要 服务器渲染处于 alpha 阶段,并可在 SDK 55 及更高版本中使用。生产环境使用需要一个已部署的服务器

服务端渲染(SSR)会在每次请求时动态生成 HTML,而 静态渲染 则是在构建时预渲染 HTML。本指南将引导你为 Expo Router 应用启用服务器渲染。

信息 使用服务端渲染时,数据加载器 会在服务器上针对每次请求执行,其结果会嵌入到 HTML 响应中。

设置

1

在项目的应用配置中启用服务器渲染:

app.json
{ "expo": { %%placeholder-start%%... %%placeholder-end%% "web": { "output": "server" }, "plugins": [ [ "expo-router", { "unstable_useServerRendering": true } ] ] } }

2

启动开发服务器:

Terminal
npx expo start

生产环境

要为生产环境导出你的应用,请运行导出命令:

Terminal
npx expo export --platform web

这会创建一个包含服务器渲染应用的 dist 目录。与静态渲染不同,不会预先生成 HTML 文件。相反,输出会包含如下所示的类似目录结构:

dist
client
  _expo
   static
    js
     web
      entry-[hash].js
    css
     [name]-[hash].css
server
  _expo
   routes.json
   server
    render.js

上面的输出在 dist 目录中包含以下目录:

  • client 目录:包含用于客户端 hydration 的 JavaScript 和 CSS bundles
  • server 目录:包含路由清单和服务器渲染模块

你可以通过运行以下命令并在浏览器中打开链接的 URL 来本地测试生产构建:

Terminal
npx expo serve

上述命令会启动一个本地服务器,在每次请求时渲染页面,模拟生产环境。

动态路由

使用服务器渲染时,动态路由会即时渲染,因此不需要 generateStaticParams 导出,并且应当移除。如果你的路由文件导出了 generateStaticParams,这些路由将改为动态处理。路由会在请求时使用 URL 中的实际参数进行渲染。

src/app/blog/[id].tsx
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 文档。此组件会包裹所有路由,并且只在服务器上运行。

src/app/+html.tsx
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 中调用 windowdocument 之类的浏览器 API

所有 +html.tsx 组件都应在其 JSX 内容中渲染它们接收到的 children 属性。

元标签

使用 expo-router<Head /> 组件为你的页面添加 meta 标签:

src/app/about.tsx
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/Expressexpo-server/adapter/express
Cloudflare Workersexpo-server/adapter/workerd
Vercel Edge Functionsexpo-server/adapter/vercel
Netlify Edge Functionsexpo-server/adapter/netlify
Bunexpo-server/adapter/bun
示例:使用 EAS Hosting 部署

EAS Hosting 开箱即支持服务器渲染。导出你的应用并使用以下命令部署:

Terminal
npx expo export --platform web

npx eas-cli@latest hosting:deploy dist

与静态渲染的比较

功能静态渲染服务器渲染
HTML 生成构建时请求时
配置web.output: 'static'web.output: 'server'
动态路由需要 generateStaticParams自动工作
需要服务器
首字节时间最快(缓存)更慢(每次请求渲染)
托管任何静态主机需要服务器运行时

常见问题

我可以在服务器渲染中使用数据加载器吗?

可以。服务器渲染可与数据加载器配合使用,在渲染之前先在服务器上获取数据。

我可以混合使用服务器渲染和静态渲染吗?

目前,Expo Router 不支持在同一个项目中混合使用服务器渲染和静态渲染。请根据你的需求选择一种输出模式。

如何缓存服务器渲染的响应?

缓存由服务器或 CDN 层处理。请根据 URL 模式或缓存头配置你的部署平台以缓存响应。

服务器渲染支持 API 路由吗?

可以。API 路由 与渲染模式相互独立。它们始终在服务器上执行。