Astro 컨테이너 API (실험적)
추가된 버전:
astro@4.9.0
컨테이너 API를 사용하면 Astro 컴포넌트를 독립적으로 렌더링할 수 있습니다.
이 실험적인 서버 측 API는 다양한 잠재적 미래 활용 가능성을 열어주지만, 현재는 vitest
와 같은 vite
환경에서 .astro
컴포넌트 출력을 테스트할 수 있도록 범위가 제한되어 있습니다.
또한 요청 시 렌더링되는 페이지나 vite
외부(예: PHP 또는 Elixir 애플리케이션 내부)의 기타 “셸” 환경에서 컨테이너를 생성하기 위한 렌더링 스크립트를 수동으로 직접 로드할 수 있습니다.
이 API를 사용하면 새 컨테이너를 생성하고, 문자열 또는 Response
를 반환하는 Astro 컴포넌트를 렌더링할 수 있습니다.
이 API는 실험적이며, 마이너 또는 패치 릴리스에서도 호환성을 깨뜨리는 변경 사항이 발생할 수 있습니다. 변경 사항은 Astro 변경 로그를 참조하세요. 이 페이지는 항상 최신 버전의 Astro에 대한 정보로 업데이트됩니다.
create()
섹션 제목: “create()”타입: (options?: AstroContainerOptions) => Promise<experimental_AstroContainer>
컨테이너의 새 인스턴스를 생성합니다.
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
기본값: false
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()”타입: (component: AstroComponentFactory; options?: ContainerRenderOptions) => Promise<string>
이 함수는 컨테이너에서 특정 컴포넌트를 렌더링합니다. 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()”타입: (component: AstroComponentFactory; options?: ContainerRenderOptions) => Promise<Response>
컴포넌트를 렌더링하고, 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?: RouteType; partial?: boolean;};
이러한 선택적 값들은 Astro 컴포넌트를 올바르게 렌더링하는 데 필요한 추가 정보를 제공하기 위해 렌더링 함수에 전달될 수 있습니다.
slots
섹션 제목: “slots”타입: Record<string, any>
<slots>
로 렌더링할 콘텐츠를 전달하는 옵션입니다.
Astro 컴포넌트가 하나의 기본 슬롯을 렌더링하는 경우, default
를 키로 사용하는 객체를 전달하세요.
import Card from "../src/components/Card.astro";
const result = await container.renderToString(Card, { slots: { default: "어떤 값" }});
컴포넌트가 명명된 슬롯을 렌더링하는 경우, 슬롯 이름을 객체 키로 사용하세요.
------<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: "환영합니다!" }});
---// TypeScript 지원을 위해 사용합니다.interface Props { name: string;};
const { name } = Astro.props;---<div> {name}</div>
request
옵션
섹션 제목: “request 옵션”타입: Request
컴포넌트가 렌더링할 경로/URL에 대한 정보를 포함하는 Request
를 전달하는 옵션입니다.
컴포넌트에서 Astro.url
또는 Astro.request
와 같은 정보를 읽어야 할 때 이 옵션을 사용합니다.
가능한 헤더나 쿠키도 주입할 수 있습니다.
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>로그인 되었습니다.</span> : <span>로그인하세요.</span> }
import Card from "../src/components/Card.astro";
test("User is in", async () => { const result = await container.renderToString(Card, { locals: { checkAuth() { return true; } } });
// 결과에 "로그인 되었습니다."라는 문자열이 포함되어야 합니다.});
test("User is out", async () => { const result = await container.renderToString(Card, { locals: { checkAuth() { return false; } } });
// 결과에 "로그인하세요."라는 문자열이 포함되어야 합니다.});
routeType
옵션
섹션 제목: “routeType 옵션”타입: RouteType
엔드포인트를 렌더링하고 있다는 것을 명시하기 위해 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() {}
// 이 코드를 테스트해야 합니다.export 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" // 테스트를 위해 POST 메서드를 지정합니다. })});const json = await response.json();
partial
옵션
섹션 제목: “partial 옵션”타입: boolean
기본값: true
astro@4.16.6
컨테이너 API가 컴포넌트를 페이지 부분처럼 렌더링할지 여부입니다. 이는 일반적으로 components.boolean
을 렌더링할 때 원하는 동작이므로 전체 페이지 셸 없이도 컴포넌트를 렌더링할 수 있습니다.
<!DOCTYPE html>
을 포함한 전체 Astro 페이지로 컴포넌트를 렌더링하려면 partial
을 false
로 설정하여 이 동작을 비활성화할 수 있습니다.
import Blog from "../src/pages/Blog.astro";
const result = await container.renderToString(Card, { partial: false});console.log(result) // HTML의 시작 부분에 `<!DOCTYPE html>`를 포함합니다.