Astro 어댑터 API
Astro는 서버 측 렌더링(SSR)으로 알려진 요청 시 렌더링을 위해 모든 클라우드 제공업체에 쉽게 배포할 수 있도록 설계되었습니다. 이 기능은 통합으로 제공되는 어댑터 를 통해 사용할 수 있습니다. 기존 어댑터를 사용하는 방법을 알아보려면 요청 시 렌더링 가이드를 참조하세요.
어댑터란 무엇입니까?
섹션 제목: 어댑터란 무엇입니까?어댑터는 요청 시 서버 렌더링을 위한 엔트리포인트 제공하는 특별한 종류의 통합입니다. 어댑터는 두 가지 작업을 수행합니다.
- 요청 처리를 위한 호스트별 API를 구현합니다.
- 호스트 규칙에 따라 빌드를 구성합니다.
어댑터 빌드
섹션 제목: 어댑터 빌드어댑터는 통합이며 통합이 수행할 수 있는 모든 작업을 수행할 수 있습니다.
어댑터는 반드시 다음과 같이 astro:config:done 후크에서 setAdapter API를 호출해야 합니다.
export default function createIntegration() { return { name: '@example/my-adapter', hooks: { 'astro:config:done': ({ setAdapter }) => { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', supportedAstroFeatures: { staticOutput: 'stable' } }); }, }, };}setAdapter에 전달된 객체는 다음과 같이 정의됩니다.
interface AstroAdapter { name: string; serverEntrypoint?: string; exports?: string[]; adapterFeatures: AstroAdapterFeatures; supportedAstroFeatures: AstroAdapterFeatureMap;}
export interface AstroAdapterFeatures { /** * Astro 미들웨어와 통신할 에지 기능을 생성합니다. */ edgeMiddleware: boolean; /** * 어댑터가 의도하는 빌드 출력 유형을 결정합니다. 기본값은 `server`입니다. */ buildOutput?: 'static' | 'server';}
export type AdapterSupportsKind = 'unsupported' | 'stable' | 'experimental' | 'deprecated' | 'limited';
export type AdapterSupportWithMessage = { support: Exclude<AdapterSupportsKind, 'stable'>; message: string; suppress?: 'default' | 'all';};
export type AdapterSupport = AdapterSupportsKind | AdapterSupportWithMessage;
export type AstroAdapterFeatureMap = { /** * 어댑터는 정적 페이지를 제공할 수 있습니다. */ staticOutput?: AdapterSupport; /** * 어댑터는 정적이거나 서버를 통해 렌더링되는 페이지를 제공할 수 있습니다. */ hybridOutput?: AdapterSupport; /** * 어댑터는 요청 시 렌더링되는 페이지를 제공할 수 있습니다. */ serverOutput?: AdapterSupport; /** * 어댑터는 i18n 도메인을 지원할 수 있습니다. */ i18nDomains?: AdapterSupport; /** * 어댑터는 `astro:env/server`에서 내보낸 `getSecret`을 지원할 수 있습니다. */ envGetSecret?: AdapterSupport; /** * 어댑터는 Sharp 이미지 서비스를 지원합니다. */ sharpImageService?: AdapterSupport;};속성은 다음과 같습니다.
- name: 로깅에 사용되는 어댑터의 고유 이름입니다.
- serverEntrypoint: 요청 시 서버 렌더링의 엔트리포인트입니다.
- exports:
createExports와 함께 사용되는 경우 명명된 내보내기 배열입니다 (아래 설명 참조). - adapterFeatures: 어댑터에서 지원해야 하는 특정 기능을 활성화하는 객체입니다. 이러한 기능은 빌드된 출력을 변경하며 어댑터는 다양한 출력을 처리하기 위해 적절한 로직을 구현해야 합니다.
- supportedAstroFeatures: Astro 내장 기능 맵입니다. 이를 통해 Astro는 어댑터가 지원할 수 없거나 지원하지 않는 기능을 판단하여 적절한 오류 메시지를 제공할 수 있습니다.
서버 엔트리포인트
섹션 제목: 서버 엔트리포인트Astro의 어댑터 API는 모든 유형의 호스트와 작동하려고 시도하며 호스트 API를 준수하는 유연한 방법을 제공합니다.
Exports
섹션 제목: Exports일부 서버리스 호스트는 handler와 같은 함수를 내보낼 것을 기대합니다.
export function handler(event, context) { // ...}어댑터 API를 사용하면 serverEntrypoint에 createExports를 구현하여 이를 달성할 수 있습니다.
import { App } from 'astro/app';
export function createExports(manifest) { const app = new App(manifest);
const handler = (event, context) => { // ... };
return { handler };}그런 다음 setAdapter를 호출하는 통합에서 exports에 이 이름을 제공합니다.
export default function createIntegration() { return { name: '@example/my-adapter', hooks: { 'astro:config:done': ({ setAdapter }) => { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', exports: ['handler'], }); }, }, };}Start
섹션 제목: Start일부 호스트는 포트를 수신하여 서버를 직접 시작하기를 기대합니다. 이러한 유형의 호스트의 경우 어댑터 API를 사용하면 번들 스크립트가 실행될 때 호출되는 start 함수를 내보낼 수 있습니다.
import { App } from 'astro/app';
export function start(manifest) { const app = new App(manifest);
addEventListener('fetch', event => { // ... });}astro/app
섹션 제목: astro/app이 모듈은 astro build를 통해 사전 빌드된 페이지를 렌더링하는 데 사용됩니다. Astro는 표준 Request 및 Response 객체를 사용합니다. 요청/응답에 대해 다른 API를 사용하는 호스트는 어댑터에서 이러한 유형으로 변환해야 합니다.
import { App } from 'astro/app';import http from 'http';
export function start(manifest) { const app = new App(manifest);
addEventListener('fetch', event => { event.respondWith( app.render(event.request) ); });}다음과 같은 메서드가 제공됩니다.
app.render()
섹션 제목: app.render()타입: (request: Request, options?: RenderOptions) => Promise<Response>
이 메서드는 요청과 일치하는 Astro 페이지를 호출하고 렌더링한 후 Response 객체에 Promise를 반환합니다. 이는 페이지를 렌더링하지 않는 API 경로에도 적용됩니다.
const response = await app.render(request);RenderOptions
섹션 제목: RenderOptions타입: {addCookieHeader?: boolean; clientAddress?: string; locals?: object; prerenderedErrorPageFetch?: (url: ErrorPagePath) => Promise<Response>; routeData?: RouteData;}
app.render() 메서드는 필수 request 인수와 addCookieHeader, clientAddress, locals, prerenderedErrorPageFetch, routeData에 대한 선택적 RenderOptions 객체를 허용합니다.
addCookieHeader
섹션 제목: addCookieHeader타입: boolean
기본값: false
Astro.cookie.set()이 작성한 모든 쿠키를 응답 헤더에 자동으로 추가할지 여부입니다.
true로 설정하면 응답의 Set-Cookie 헤더에 쉼표로 구분된 키-값 쌍으로 추가됩니다. 표준 response.headers.getSetCookie() API를 사용하여 개별적으로 읽을 수 있습니다. false (기본값)로 설정하면 App.getSetCookieFromResponse(response)에서만 쿠키를 사용할 수 있습니다.
const response = await app.render(request, { addCookieHeader: true });clientAddress
섹션 제목: clientAddress타입: string
기본값: request[Symbol.for("astro.clientAddress")]
페이지에서는 Astro.clientAddress로, API 경로 및 미들웨어에서는 ctx.clientAddress로 사용할 수 있는 클라이언트 IP 주소입니다.
아래 예시에서는 x-forwarded-for 헤더를 읽고 이를 clientAddress로 전달합니다. 이 값은 사용자가 Astro.clientAddress로 사용할 수 있게 됩니다.
const clientAddress = request.headers.get("x-forwarded-for");const response = await app.render(request, { clientAddress });locals
섹션 제목: locals타입: object
요청 수명 주기 동안 정보를 저장하고 액세스하는 데 사용되는 context.locals 객체입니다.
아래 예시에서는 x-private-header라는 헤더를 읽고 이를 객체로 구문 분석한 후 locals에 전달하려고 시도합니다. 그런 다음 미들웨어 함수에 전달될 수 있습니다.
const privateHeader = request.headers.get("x-private-header");let locals = {};try { if (privateHeader) { locals = JSON.parse(privateHeader); }} finally { const response = await app.render(request, { locals });}prerenderedErrorPageFetch
섹션 제목: prerenderedErrorPageFetch타입: (url: ErrorPagePath) => Promise<Response>
기본값: fetch
astro@5.6.0
사전 렌더링된 오류 페이지를 가져오는 사용자 정의 구현을 제공할 수 있는 함수입니다.
이 함수는 기본 fetch() 동작을 재정의하는 데 사용됩니다. 예를 들어 fetch()를 사용할 수 없거나 서버 자체에서 서버를 호출할 수 없는 경우에 사용됩니다.
다음 예제는 HTTP 호출을 수행하는 대신 디스크에서 500.html과 404.html을 읽습니다.
return app.render(request, { prerenderedErrorPageFetch: async (url: string): Promise<Response> => { if (url.includes("/500")) { const content = await fs.promises.readFile("500.html", "utf-8"); return new Response(content, { status: 500, headers: { "Content-Type": "text/html" }, }); }
const content = await fs.promises.readFile("404.html", "utf-8"); return new Response(content, { status: 404, headers: { "Content-Type": "text/html" }, });});제공되지 않으면 Astro는 오류 페이지를 가져오는 기본 동작으로 대체합니다.
routeData
섹션 제목: routeData타입: RouteData
기본값: app.match(request)
렌더링할 경로를 이미 알고 있는 경우 integrationRouteData에 대한 값을 제공하세요. 그렇게 하면 렌더링할 경로를 결정하기 위해 app.match에 대한 내부 호출을 우회하게 됩니다.
const routeData = app.match(request);if (routeData) { return app.render(request, { routeData });} else { /* 어댑터별 404 응답 */ return new Response(..., { status: 404 });}app.match()
섹션 제목: app.match()타입: (request: Request) => RouteData | undefined
이 메서드는 요청이 Astro 앱의 라우팅 규칙과 일치하는지 확인하는 데 사용됩니다.
if(app.match(request)) { const response = await app.render(request);}Astro가 404.astro 파일을 제공하면 404를 처리하기 때문에 일반적으로 .match를 사용하지 않고 app.render(request)를 호출할 수 있습니다. 404를 다른 방식으로 처리하려면 app.match(request)를 사용하세요.
astro add를 통한 설치 허용
섹션 제목: astro add를 통한 설치 허용astro add 명령을 사용하면 사용자가 프로젝트에 통합 및 어댑터를 쉽게 추가할 수 있습니다. 이 도구를 사용하여 여러분의 어댑터를 설치하려면 package.json 파일의 keywords 필드에 astro-adapter를 추가하세요:
{ "name": "example", "keywords": ["astro-adapter"],}어댑터를 npm에 게시한 후, astro add example을 실행하면 package.json 파일에 지정된 피어 종속성과 함께 패키지가 설치됩니다. 또한 사용자에게 프로젝트 구성을 수동으로 업데이트하도록 지시할 것입니다.
Astro 기능
섹션 제목: Astro 기능
추가된 버전:
astro@3.0.0
Astro 기능은 어댑터가 Astro에 기능을 지원할 수 있는지 여부와 어댑터의 지원 수준을 알려주는 방법입니다.
이러한 속성을 사용할 때 Astro는 다음을 수행합니다.
- 특정 유효성 검사를 실행합니다.
- 로그에 컨텍스트 정보를 내보냅니다.
이러한 작업은 기능의 지원 여부, 지원 수준, 원하는 로깅의 양, 사용자의 자체 구성에 따라 다르게 실행됩니다.
다음 구성은 이 어댑터가 Sharp 기반의 내장 이미지 서비스에 대한 실험적 지원을 가지고 있음을 Astro에 알려줍니다.
export default function createIntegration() { return { name: '@example/my-adapter', hooks: { 'astro:config:done': ({ setAdapter }) => { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', supportedAstroFeatures: { sharpImageService: 'experimental' } }); }, }, };}Sharp 이미지 서비스가 사용되는 경우, Astro는 어댑터의 지원 상태에 따라 터미널에 경고와 오류를 기록할 것입니다.
[@example/my-adapter] The feature is experimental and subject to issues or changes.
[@example/my-adapter] The currently selected adapter `@example/my-adapter` is not compatible with the service "Sharp". Your project will NOT be able to build.사용자에게 더 많은 맥락을 제공하기 위해 추가적인 메시지를 제공할 수 있습니다:
export default function createIntegration() { return { name: '@example/my-adapter', hooks: { 'astro:config:done': ({ setAdapter }) => { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', supportedAstroFeatures: { sharpImageService: { support: 'limited', message: 'This adapter has limited support for Sharp. Certain features may not work as expected.' } } }); }, }, };}suppress
섹션 제목: suppress타입: 'default' | 'all'
astro@5.9.0
새로운 기능
어댑터의 기능 지원 여부에 대한 로그 메시지 중 일부 또는 전부를 표시하지 않도록 설정하는 옵션입니다.
Astro의 기본 로그 메시지가 사용자 지정 message와 함께 사용될 때 중복되거나 혼란을 줄 수 있다면, suppress: "default" 옵션을 사용하여 기본 메시지를 숨기고 사용자 지정 메시지만 로깅할 수 있습니다.
export default function createIntegration() { return { name: '@example/my-adapter', hooks: { 'astro:config:done': ({ setAdapter }) => { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', supportedAstroFeatures: { sharpImageService: { support: 'limited', message: 'The adapter has limited support for Sharp. It will be used for images during build time, but will not work at runtime.', suppress: 'default' // 사용자 지정 메시지는 기본값보다 더 상세합니다. } } }); }, }, };}또한 suppress: "all"을 사용하여 기능 지원 관련 메시지를 모두 표시하지 않을 수도 있습니다. 이 옵션은 해당 기능을 사용하지 않는 구성 설정이 있는 경우와 같이 이러한 메시지가 사용자에게 도움이 되지 않는 특정 상황에 유용합니다. 예를 들어, 어댑터에서 Sharp 지원에 대한 메시지를 기록하지 않도록 선택할 수 있습니다.
export default function createIntegration() { return { name: '@example/my-adapter', hooks: { 'astro:config:done': ({ setAdapter }) => { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', supportedAstroFeatures: { sharpImageService: { support: 'limited', message: 'This adapter has limited support for Sharp. Certain features may not work as expected.', suppress: 'all' } } }); }, }, };}어댑터 기능
섹션 제목: 어댑터 기능내보낸 파일의 출력을 변경하는 기능 세트입니다. 어댑터가 이러한 기능을 선택하면 특정 후크에서 추가 정보를 얻게 됩니다.
edgeMiddleware
섹션 제목: edgeMiddleware타입: boolean
요청 시 렌더링되는 미들웨어 코드가 빌드 타임에 번들링될지 여부를 정의합니다.
활성화되면, 이는 빌드 타임에 모든 페이지에서 미들웨어 코드가 번들링되고 가져와지는 것을 방지합니다:
export default function createIntegration() { return { name: '@example/my-adapter', hooks: { 'astro:config:done': ({ setAdapter }) => { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', adapterFeatures: { edgeMiddleware: true } }); }, }, };}그런 다음, 파일 시스템의 실제 파일에 대한 URL인 middlewareEntryPoint를 제공하는 astro:build:ssr 훅을 사용합니다.
export default function createIntegration() { return { name: '@example/my-adapter', hooks: { 'astro:config:done': ({ setAdapter }) => { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', adapterFeatures: { edgeMiddleware: true } }); },
'astro:build:ssr': ({ middlewareEntryPoint }) => { // 이 속성이 존재하는지 확인하는 것을 잊지 마세요. 어댑터가 이 기능을 사용하도록 설정하지 않은 경우 `undefined`가 될 것입니다. if (middlewareEntryPoint) { createEdgeMiddleware(middlewareEntryPoint) } } }, };}
function createEdgeMiddleware(middlewareEntryPoint) { // 번들러를 사용하여 새로운 물리적 파일을 생성하세요.}envGetSecret
섹션 제목: envGetSecret타입: AdapterSupportsKind
이는 어댑터가 env.schema에서 사용자가 구성한 비밀을 검색할 수 있도록 하는 기능입니다.
어댑터에 유효한 AdapterSupportsKind 값을 전달하여 기능을 활성화하세요:
export default function createIntegration() { return { name: '@example/my-adapter', hooks: { 'astro:config:done': ({ setAdapter }) => { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', adapterFeatures: { envGetSecret: 'stable' } }); }, }, };}astro/env/setup 모듈을 통해 getSecret() 구현을 제공할 수 있습니다. 서버 엔트리포인트에서 가능한 한 빨리 setGetEnv()를 호출하세요:
import { App } from 'astro/app';import { setGetEnv } from "astro/env/setup"
setGetEnv((key) => process.env[key])
export function createExports(manifest) { const app = new App(manifest); const handler = (event, context) => { // ... };
return { handler };}비밀을 지원하는 경우, 환경 변수가 요청에 연결되어 있을 때 getSecret() 전에 setGetEnv()를 호출해야 합니다:
import type { SSRManifest } from 'astro';import { App } from 'astro/app';import { setGetEnv } from 'astro/env/setup';import { createGetEnv } from '../utils/env.js';
type Env = { [key: string]: unknown;};
export function createExports(manifest: SSRManifest) { const app = new App(manifest);
const fetch = async (request: Request, env: Env) => { setGetEnv(createGetEnv(env));
const response = await app.render(request);
return response; };
return { default: { fetch } };}buildOutput
섹션 제목: buildOutput타입: 'static' | 'server'
astro@5.0.0
이 속성을 사용하면 빌드의 특정 출력 형태를 강제할 수 있습니다. 이는 특정 출력 유형에서만 작동하는 어댑터에 유용할 수 있습니다. 예를 들어, 어댑터가 정적 웹사이트를 기대하지만 호스트별 파일을 생성하기 위해 어댑터를 사용하는 경우가 있습니다. 지정하지 않으면 기본값은 server입니다.
export default function createIntegration() { return { name: '@example/my-adapter', hooks: { 'astro:config:done': ({ setAdapter }) => { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', adapterFeatures: { buildOutput: 'static' } }); }, }, };}experimentalStaticHeaders
섹션 제목: experimentalStaticHeaders타입: true | false
astro@5.9.3
새로운 기능
이 기능을 활성화하면 Astro는 정적 페이지에서 내보낸 Headers 맵을 반환합니다. 이 맵은 experimentalRouteToHeaders이며, astro:build:generated 훅에서 사용할 수 있습니다.
헤더 값은 애플리케이션에서 활성화되거나 사용되는 기능에 따라 변경될 수 있습니다.
예를 들어, CSP가 활성화된 경우 <meta http-equiv="content-security-policy"> 요소는 정적 페이지에 추가되지 않습니다. 대신 experimentalRouteToHeaders 맵에서 해당 content를 사용할 수 있습니다.
export default function createIntegration() { return { name: '@example/my-adapter', hooks: { 'astro:config:done': ({ setAdapter }) => { setAdapter({ name: '@example/my-adapter', serverEntrypoint: '@example/my-adapter/server.js', adapterFeatures: { experimentalStaticHeaders: true } }); }, 'astro:build:generated': ({ experimentalRouteToHeaders }) => { // experimentalRouteToHeaders를 사용하여 원하는 가상 호스트의 구성 파일을 생성하세요. } },};}