Saltar al contenido

API de Contenedor de Astro (experimental)

Añadido en: astro@4.9.0

La API de Contenedor te permite renderizar componentes de Astro en aislamiento.

Esta API experimental del lado del servidor abre una variedad de posibles usos futuros, pero actualmente está limitada a permitir la comprobación de la salida de componentes de .astro en entornos de vite como vitest.

También te permite cargar manualmente scripts de renderizado para crear contenedores en páginas renderizadas bajo demanda u otros entornos de "shell" fuera de vite (por ejemplo, dentro de una aplicación PHP o Elixir).

Esta API te permite crear un nuevo contenedor y renderizar un componente de Astro devolviendo una cadena o una Response.

Esta API es experimental y está sujeta a cambios decisivos, incluso en versiones menores o de parches. Consulta el CHANGELOG de Astro para ver los cambios a medida que ocurren. Esta página siempre se actualizará con la información más reciente para la última versión de Astro.

Tipo: (options?: AstroContainerOptions) => Promise<experimental_AstroContainer>

Crea una nueva instancia del contenedor.

import { experimental_AstroContainer } from "astro/container";
const container = await experimental_AstroContainer.create();

Acepta un objeto con las siguientes opciones:

export type AstroContainerOptions = {
streaming?: boolean;
renderers?: AddServerRenderer[];
};
export type AddServerRenderer =
| {
renderer: NamedSSRLoadedRendererValue;
name: never;
}
| {
renderer: SSRLoadedRendererValue;
name: string;
};

Type: boolean
Default: false

Permite renderizar componentes utilizando streaming de HTML.

Type: AddServerRenderer[]
Default: []

Una lista de renderizadores de cliente cargados que requiere el componente. Usa esto si tu componente .astro renderiza cualquier componente de framework de UI o MDX utilizando una integración oficial de Astro (por ejemplo, React, Vue, etc.).

Los renderizadores se pueden añadir a través de la API de Contenedor automáticamente para aplicaciones estáticas, o casos donde no se llama al contenedor en tiempo de ejecución (por ejemplo, haciendo pruebas con vitest).

Para aplicaciones renderizadas bajo demanda, o casos en los los que se llama al contenedor en tiempo de ejecución o dentro de otros "shells" (por ejemplo, PHP, Ruby, Java, etc.), los renderizadores deben importarse manualmente.

Añadir un renderizador a través de la API de Contenedor

Sección titulada “Añadir un renderizador a través de la API de Contenedor”

Para cada integración oficial de Astro, importa y usa la función auxiliar getContainerRenderer() desde su punto de entrada dedicado container-renderer para exponer sus scripts de renderizado de cliente y servidor. Estos puntos de entrada están disponibles para @astrojs/react, @astrojs/preact, @astrojs/solid-js, @astrojs/svelte, @astrojs/vue y @astrojs/mdx.

Para los paquetes de renderizadores fuera de la organización npm @astrojs, busca en su documentación getContainerRenderer() o una función similar proporcionada.

Cuando se usa vite (vitest, integraciones de Astro, etc.), los renderizadores se cargan con la función loadRenderers() desde el módulo virtual astro:container.

El siguiente ejemplo proporciona el objeto necesario para renderizar un componente de Astro que renderiza un componente de React y un componente de Svelte:

import { getContainerRenderer as reactContainerRenderer } from "@astrojs/react/container-renderer";
import { getContainerRenderer as svelteContainerRenderer } from "@astrojs/svelte/container-renderer";
import { loadRenderers } from "astro:container";
const renderers = await loadRenderers([reactContainerRenderer(), svelteContainerRenderer()]);
const container = await experimental_AstroContainer.create({
renderers
})
const result = await container.renderToString(ReactWrapper);

Cuando se llama al contenedor en tiempo de ejecución, o dentro de otros "shells", las funciones auxiliares del módulo virtual astro:container no están disponibles. Debes importar los renderizadores de servidor y cliente necesarios manualmente y almacenarlos dentro del contenedor usando addServerRenderer y addClientRenderer.

Los renderizadores de servidor son necesarios para construir tu proyecto, y deben almacenarse en el contenedor para cada framework utilizado. Los renderizadores de cliente también son necesarios para hidratar cualquier componente del lado del cliente utilizando directivas client:*.

Solo se necesita una instrucción de importación por framework. Importar un renderizador hace que tanto los renderizadores de servidor como de cliente estén disponibles para tu contenedor. Sin embargo, los renderizadores de servidor deben añadirse a tu contenedor antes que los renderizadores de cliente. Esto permite que todo el contenedor se renderice primero y luego se hidrate cualquier componente interactivo.

El siguiente ejemplo importa manualmente los renderizadores de servidor necesarios para poder mostrar componentes estáticos de Vue y páginas .mdx. Además, añade renderizadores tanto de servidor como de cliente para componentes interactivos de 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" });

Tipo: (component: AstroComponentFactory; options?: ContainerRenderOptions) => Promise<string>

Esta función renderiza un componente especificado dentro de un contenedor. Toma un componente de Astro como argumento y devuelve una cadena que representa el HTML/contenido renderizado por el componente de Astro.

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);

Bajo el capó, esta función llama a renderToResponse() y a Response.text().

También acepta un objeto como segundo argumento que puede contener una serie de opciones.

Tipo: (component: AstroComponentFactory; options?: ContainerRenderOptions) => Promise<Response>

Renderiza un componente y devuelve un objeto 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);

También acepta un objeto como segundo argumento que puede contener una serie de opciones.

Tanto renderToResponse() como renderToString() aceptan un objeto como segundo argumento:

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;
};

Estos valores opcionales se pueden pasar a la función de renderizado con el fin de proporcionar información adicional necesaria para que un componente de Astro se renderice correctamente.

Type: Record<string, any>

Una opción para pasar contenido a renderizar con <slots>.

Si tu componente de Astro renderiza un slot por defecto, pasa un objeto con default como clave:

import Card from "../src/components/Card.astro";
const result = await container.renderToString(Card, {
slots: { default: "Some value" }
});

Si tu componente renderiza slots nombrados, usa los nombres de los slots como las claves del objeto:

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

También puedes renderizar componentes en cascada:

---
---
<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)
}
});

Type: Record<string, unknown>

Una opción para pasar propiedades para componentes de Astro.

import Card from "../src/components/Card.astro";
const result = await container.renderToString(Card, {
props: { name: "Hello, world!" }
});
---
// For TypeScript support
interface Props {
name: string;
};
const { name } = Astro.props;
---
<div>
{name}
</div>

Type: Request

Una opción para pasar una Request con información sobre la ruta/URL que el componente renderizará.

Usa esta opción cuando tu componente necesite leer información como Astro.url o Astro.request.

También puedes inyectar posibles cabeceras o cookies.

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

Type: Record<string, string | undefined>

Un objeto para pasar información sobre el parámetro de ruta a un componente de Astro responsable de generar rutas dinámicas.

Usa esta opción cuando tu componente necesite un valor para Astro.params para poder generar una sola ruta dinámicamente.

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

Type: App.Locals

Una opción para pasar información de Astro.locals para renderizar tu componente.

Usa esta opción cuando tu componente necesite información almacenada durante el ciclo de vida de una solicitud para poder renderizarse, como el estado de inicio de sesión.

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

Type: RouteType

Una opción disponible al usar renderToResponse() para especificar que estás renderizando un endpoint:

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();

Para probar tu endpoint en métodos como POST, PATCH, etc., usa la opción request para llamar a la función correcta:

export function GET() {}
// need to test this
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" // Specify POST method for testing
})
});
const json = await response.json();

Type: boolean
Default: true

Añadido en: astro@4.16.6

Indica si la API de Contenedor renderiza o no los componentes como si fueran parciales de página. El valor por defecto de true renderiza el componente en aislamiento sin una estructura de página completa.

Para renderizar un componente como una página de Astro completa, incluyendo <!DOCTYPE html>, puedes desactivar este comportamiento estableciendo partial en 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
Contribuir Comunidad Patrocinar