콘텐츠로 이동

Astro 컨테이너 API (실험적)

추가된 버전: astro@4.9.0

컨테이너 API를 사용하면 Astro 컴포넌트를 독립적으로 렌더링할 수 있습니다.

이 실험적인 서버 측 API는 다양한 잠재적 미래 활용 가능성을 열어주지만, 현재는 vitest와 같은 vite 환경에서 .astro 컴포넌트 출력을 테스트할 수 있도록 범위가 제한되어 있습니다.

또한 요청 시 렌더링되는 페이지나 vite 외부(예: PHP 또는 Elixir 애플리케이션 내부)의 기타 “셸” 환경에서 컨테이너를 생성하기 위한 렌더링 스크립트를 수동으로 직접 로드할 수 있습니다.

이 API를 사용하면 새 컨테이너를 생성하고, 문자열 또는 Response를 반환하는 Astro 컴포넌트를 렌더링할 수 있습니다.

이 API는 실험적이며, 마이너 또는 패치 릴리스에서도 호환성을 깨뜨리는 변경 사항이 발생할 수 있습니다. 변경 사항은 Astro 변경 로그를 참조하세요. 이 페이지는 항상 최신 버전의 Astro에 대한 정보로 업데이트됩니다.

타입: (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;
};

타입: boolean
기본값: false

HTML 스트리밍을 사용한 컴포넌트 렌더링을 활성화합니다.

타입: 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:containerloadRenderers() 함수를 통해 로드됩니다.

다음은 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 가상 모듈의 도우미 함수를 사용할 수 없습니다. 필요한 서버 및 클라이언트 렌더러를 수동으로 직접 가져와 addServerRendereraddClientRenderer를 사용하여 컨테이너에 저장해야 합니다.

프로젝트 빌드에는 서버 렌더러가 필요하며, 사용된 모든 프레임워크별로 컨테이너에 저장되어야 합니다. 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" });

타입: (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()를 호출합니다.

또한 두 번째 인자로 여러 옵션을 포함할 수 있는 객체를 받습니다.

타입: (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 컴포넌트를 올바르게 렌더링하는 데 필요한 추가 정보를 제공하기 위해 렌더링 함수에 전달될 수 있습니다.

타입: 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)
}
});

타입: 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

컴포넌트가 렌더링할 경로/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"
}
})
});

타입: 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"
}
});

타입: 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

엔드포인트를 렌더링하고 있다는 것을 명시하기 위해 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();

타입: boolean
기본값: true

추가된 버전: astro@4.16.6

컨테이너 API가 컴포넌트를 페이지 부분처럼 렌더링할지 여부입니다. 이는 일반적으로 components.boolean을 렌더링할 때 원하는 동작이므로 전체 페이지 셸 없이도 컴포넌트를 렌더링할 수 있습니다.

<!DOCTYPE html>을 포함한 전체 Astro 페이지로 컴포넌트를 렌더링하려면 partialfalse로 설정하여 이 동작을 비활성화할 수 있습니다.

import Blog from "../src/pages/Blog.astro";
const result = await container.renderToString(Card, {
partial: false
});
console.log(result) // HTML의 시작 부분에 `<!DOCTYPE html>`를 포함합니다.
기여하기 커뮤니티 후원하기