Astro 容器 API (实验性)
新增于: astro@4.9.0
容器 API 允许你独立地渲染 Astro 组件。
这个实验性的服务端 API 解锁了多种潜在的未来用途,但目前其范围仅限于在 vite
环境(如 vitest
)中对 测试 .astro
组件的输出。
它还允许你手动加载渲染脚本,以便在按需渲染的页面或其他 vite
之外的“外壳”环境(例如,在 PHP 或 Elixir 应用程序内部)中创建容器。
该 API 允许你创建一个新的容器,并渲染一个 Astro 组件,返回一个字符串或一个Response
。
此 API 是实验性的,可能会发生破坏性更改,即使是在次要版本或补丁版本中。请查阅 Astro 更新日志以了解发生的更改。此页面将始终更新为最新版 Astro 的最新信息。
create()
标题为“create()”的部分创建一个新的容器实例。
import { experimental_AstroContainer } from "astro/container";
const container = await experimental_AstroContainer.create();
它接受一个包含以下选项的对象
export type AstroContainerOptions = { streaming?: boolean; renderers?: AddServerRenderer[];};
export type AddServerRenderer = | { renderer: NamedSSRLoadedRendererValue; name: never; } | { renderer: SSRLoadedRendererValue; name: string; };
streaming
选项
标题为“streaming 选项”的部分类型: boolean
启用使用HTML 流式传输来渲染组件。
renderers
选项
标题为“renderers 选项”的部分类型: AddServerRenderer[]
组件所需的已加载的客户端渲染器列表。如果你的 .astro
组件使用官方 Astro 集成(例如 React、Vue 等)渲染任何UI 框架组件或 MDX,请使用此选项。
对于静态应用程序,或容器不在运行时调用的情况(例如,使用 vitest
进行测试),渲染器可以通过容器 API 自动添加。
对于按需渲染的应用程序,或容器在运行时或在其他“外壳”(例如 PHP、Ruby、Java 等)内部调用的情况,必须手动导入渲染器。
通过容器 API 添加渲染器
标题为“通过容器 API 添加渲染器”的部分对于每个官方 Astro 集成,导入并使用 getContainerRenderer()
辅助函数来暴露其客户端和服务器渲染脚本。这些脚本可用于 @astrojs/react
、@astrojs/preact
、@astrojs/solid-js
、@astrojs/svelte
、@astrojs/vue
和 @astrojs/mdx
。
对于 @astrojs
npm 组织之外的渲染器包,请在其文档中查找 getContainerRenderer()
或提供的类似函数。
当使用 vite
(vitest
、Astro 集成等)时,渲染器会从虚拟模块 astro:container
中使用 loadRenderers()
函数加载。
在 vite
之外或对于按需使用,你必须手动加载渲染器。
以下示例提供了渲染一个同时渲染 React 组件和 Svelte 组件的 Astro 组件所需的对象
import { getContainerRenderer as reactContainerRenderer } from "@astrojs/react";import { getContainerRenderer as svelteContainerRenderer } from "@astrojs/svelte";import { loadRenderers } from "astro:container";
const renderers = await loadRenderers([reactContainerRenderer(), svelteContainerRenderer()]);const container = await experimental_AstroContainer.create({ renderers})const result = await container.renderToString(ReactWrapper);
手动添加渲染器
标题为“手动添加渲染器”的部分当容器在运行时或在其他“外壳”内部调用时,astro:container
虚拟模块的辅助函数不可用。你必须手动导入必要的服务器和客户端渲染器,并使用 addServerRenderer
和 addClientRenderer
将它们存储在容器内部。
构建项目需要服务器渲染器,并且必须为使用的每个框架将其存储在容器中。此外,使用client:*
指令激活任何客户端组件也需要客户端渲染器。
每个框架只需要一个导入语句。导入一个渲染器会使服务器和客户端渲染器都可用于你的容器。但是,服务器渲染器必须在客户端渲染器之前添加到你的容器中。这允许你的整个容器首先渲染,然后再激活任何交互式组件。
以下示例手动导入必要的服务器渲染器,以便能够显示静态 Vue 组件和 .mdx
页面。它还为交互式 React 组件添加了服务器和客户端渲染器。
import reactRenderer from "@astrojs/react/server.js";import vueRenderer from "@astrojs/vue/server.js";import mdxRenderer from "@astrojs/mdx/server.js";
const container = await experimental_AstroContainer.create();container.addServerRenderer({renderer: vueRenderer});container.addServerRenderer({renderer: mdxRenderer});
container.addServerRenderer({ renderer: reactRenderer });container.addClientRenderer({ name: "@astrojs/react", entrypoint: "@astrojs/react/client.js" });
renderToString()
标题为“renderToString()”的部分此函数在容器内渲染指定的组件。它以一个 Astro 组件作为参数,并返回一个表示该 Astro 组件渲染的 HTML/内容的字符串。
import { experimental_AstroContainer } from "astro/container";import Card from "../src/components/Card.astro";
const container = await experimental_AstroContainer.create();const result = await container.renderToString(Card);
在底层,此函数调用 renderToResponse
并调用 Response.text()
。
它还接受一个对象作为第二个参数,该对象可以包含多个选项。
renderToResponse()
标题为“renderToResponse()”的部分它渲染一个组件,并返回一个 Response
对象。
import { experimental_AstroContainer } from "astro/container";import Card from "../src/components/Card.astro";
const container = await experimental_AstroContainer.create();const result = await container.renderToResponse(Card);
它还接受一个对象作为第二个参数,该对象可以包含多个选项。
渲染选项
标题为“渲染选项”的部分renderToResponse
和 renderToString
都接受一个对象作为它们的第二个参数
export type ContainerRenderOptions = { slots?: Record<string, any>; props?: Record<string, unknown>; request?: Request; params?: Record<string, string | undefined>; locals?: App.Locals; routeType?: "page" | "endpoint";};
这些可选值可以传递给渲染函数,以便提供 Astro 组件正确渲染所需的附加信息。
slots
标题为“slots”的部分类型: Record<string, any>
;
一个用于传递内容以通过 <slots>
渲染的选项。
如果你的 Astro 组件渲染一个默认插槽,请传递一个以 default
为键的对象
import Card from "../src/components/Card.astro";
const result = await container.renderToString(Card, { slots: { default: "Some value" }});
如果你的组件渲染具名插槽,请使用插槽名称作为对象键
------<div> <slot name="header" /> <slot name="footer" /></div>
import Card from "../src/components/Card.astro";
const result = await container.renderToString(Card, { slots: { header: "Header content", footer: "Footer" }});
你还可以级联渲染组件
------<div> <slot name="header" /> <slot name="footer" /></div>
import Card from "../src/components/Card.astro";import CardHeader from "../src/components/CardHeader.astro";import CardFooter from "../src/components/CardFooter.astro";
const result = await container.renderToString(Card, { slots: { header: await container.renderToString(CardHeader), footer: await container.renderToString(CardFooter) }});
props
选项
标题为“props 选项”的部分类型: Record<string, unknown>
一个用于为 Astro 组件传递属性的选项。
import Card from "../src/components/Card.astro";
const result = await container.renderToString(Card, { props: { name: "Hello, world!" }});
---// For TypeScript supportinterface Props { name: string;};
const { name } = Astro.props;---<div> {name}</div>
request
选项
标题为“request 选项”的部分类型: Request
一个用于传递 Request
对象的选项,其中包含组件将渲染的路径/URL 信息。
当你的组件需要读取像 Astro.url
或 Astro.request
这样的信息时,请使用此选项。
你还可以注入可能的请求头或 cookie。
import Card from "../src/components/Card.astro";
const result = await container.renderToString(Card, { request: new Request("https://example.com/blog", { headers: { "x-some-secret-header": "test-value" } })});
params
选项
标题为“params 选项”的部分类型: Record<string, string | undefined>
;
一个用于将路径参数信息传递给负责生成动态路由的 Astro 组件的对象。
当你的组件需要 Astro.params
的值以动态生成单个路由时,请使用此选项。
---const { locale, slug } = Astro.params;---<div></div>
import LocaleSlug from "../src/components/[locale]/[slug].astro";
const result = await container.renderToString(LocaleSlug, { params: { locale: "en", slug: "getting-started" }});
locals
选项
标题为“locals 选项”的部分类型: App.Locals
一个用于从 Astro.locals
传递信息以渲染组件的选项。
当你的组件需要请求生命周期中存储的信息(例如登录状态)才能渲染时,请使用此选项。
---const { checkAuth } = Astro.locals;const isAuthenticated = checkAuth();---{isAuthenticated ? <span>You're in</span> : <span>You're out</span> }
import Card from "../src/components/Card.astro";
test("User is in", async () => { const result = await container.renderToString(Card, { locals: { checkAuth() { return true; } } });
// assert result contains "You're in"});
test("User is out", async () => { const result = await container.renderToString(Card, { locals: { checkAuth() { return false; } } });
// assert result contains "You're out"});
routeType
选项
标题为“routeType 选项”的部分类型: "page" | "endpoint"
使用 renderToResponse
时可用的一个选项,用于指定你正在渲染一个端点
container.renderToString(Endpoint, { routeType: "endpoint" });
import * as Endpoint from "../src/pages/api/endpoint.js";
const response = await container.renderToResponse(Endpoint, { routeType: "endpoint"});const json = await response.json();
要在 POST
、PATCH
等方法上测试你的端点,请使用 request
选项来调用正确的函数
export function GET() {}
// need to test thisexport function POST() {}
import * as Endpoint from "../src/pages/api/endpoint.js";
const response = await container.renderToResponse(Endpoint, { routeType: "endpoint", request: new Request("https://example.com", { method: "POST" // Specify POST method for testing })});const json = await response.json();
partial
选项
标题为“partial 选项”的部分类型: boolean
默认值: true
astro@4.16.6
容器 API 是否像渲染页面局部片段一样渲染组件。当你渲染 components.boolean
时,这通常是你想要的行为,这样你就可以在没有完整页面外壳的情况下渲染组件。
要将组件渲染为完整的 Astro 页面,包括 <!DOCTYPE html>
,你可以通过将 partial
设置为 false
来选择退出此行为
import Blog from "../src/pages/Blog.astro";
const result = await container.renderToString(Card, { partial: false});console.log(result) // includes `<!DOCTYPE html>` at the beginning of the HTML