컨텐츠로 건너뛰기

Astro 콘텐츠 로더 API

Astro의 콘텐츠 로더 API를 사용하면 로컬 또는 원격의 모든 소스에서 데이터를 로드하고 콘텐츠 컬렉션을 관리하기 위해 Astro의 콘텐츠 레이어와 상호 작용할 수 있습니다.

Astro 로더를 사용하면 페이지와 컴포넌트에서 사용할 수 있는 콘텐츠 컬렉션에 데이터를 로드할 수 있습니다. 내장된 glob()file() 로더는 파일 시스템에서 콘텐츠를 로드하는 데 사용되며, 다른 소스에서 콘텐츠를 로드하기 위한 자체 로더를 만들 수 있습니다.

각 컬렉션에는 스키마에 정의된 로더가 필요합니다. 프로젝트의 src/content.config.ts 파일에서 로더를 인라인으로 정의하거나, 여러 컬렉션 간에 하나의 로더를 공유하거나, 심지어 로더를 NPM 패키지로 게시하여 다른 사람들과 공유하고 통합 라이브러리에 포함시킬 수도 있습니다.

로더는 항목 배열을 반환하는 단순한 함수로 정의하거나, 로딩 프로세스를 더 잘 제어할 수 있는 강력한 객체 콘텐츠 로더 API로 정의할 수 있습니다.

인라인 로더는 항목의 배열이나 객체를 반환하는 비동기 함수입니다. 이것은 특히 src/content.config.ts 파일에 인라인으로 정의된 간단한 로더에 사용하세요.

이 함수는 비동기일 수 있으며 각각 고유한 id 필드를 포함하는 항목의 배열이나, 각 키가 고유 ID이고 각 값이 항목인 객체를 반환해야 합니다. 로더가 호출될 때마다 저장소를 지우고 모든 항목을 다시 로드합니다.

src/content.config.ts
const countries = defineCollection({
loader: async () => {
const response = await fetch("https://restcountries.com/v3.1/all");
const data = await response.json();
// id 속성을 가진 항목의 배열이나
// ID를 키로, 항목을 값으로 가지는 객체를 반환해야 합니다
return data.map((country) => ({
id: country.cca3,
...country,
}));
},
schema: /* ... */
});

로더는 빌드 시점에 데이터를 가져오고 데이터 저장소를 업데이트하기 위해 호출되는 load() 메서드를 가진 객체입니다. 이는 항목을 점진적으로 업데이트하거나 필요한 경우에만 저장소를 지우는 것을 허용합니다. 또한 데이터를 검증하고 정적 타입을 생성하는 데 사용할 수 있는 항목의 스키마를 정의할 수 있습니다.

권장되는 패턴은 Astro 통합이나 Vite 플러그인을 정의하는 것과 같은 방식으로, 구성 옵션을 받아 로더 객체를 반환하는 함수를 정의하는 것입니다.

loader.ts
import type { Loader, LoaderContext } from 'astro/loaders';
import { z } from 'astro:content';
import { loadFeedData } from "./feed.js";
// 로더에 필요한 모든 옵션을 정의
export function myLoader(options: { url: string, apiKey: string }): Loader {
// 로더 구성
const feedUrl = new URL(options.url);
// 로더 객체 반환
return {
name: "my-loader",
// 컬렉션 업데이트 시 호출
load: async (context: LoaderContext): Promise<void> => {
// 데이터 로드 및 저장소 업데이트
const response = await loadFeedData(feedUrl, options.apiKey);
},
// 선택적으로, 항목의 스키마 정의
// 사용자 정의 스키마에 의해 재정의됨
schema: async () => z.object({
// ...
})
};
}

이러한 구성 옵션은 컬렉션을 정의할 때 설정할 수 있습니다:

src/content.config.ts
import { defineCollection, z } from 'astro:content';
import myLoader from '../../loader.ts';
const blog = defineCollection({
loader: myLoader({
url: "https://api.example.com/posts",
apiKey: "my-secret",
}),
schema: /* ... */
});

인라인 로더를 위한 API는 매우 간단하며 위에서 보여드렸습니다. 이 섹션에서는 객체 로더를 정의하기 위한 API를 보여줍니다.

로더 객체는 다음과 같은 속성을 가집니다:

타입: string

로그 및 조건부 로딩에 사용되는 로더의 고유한 이름입니다.

타입: (context: LoaderContext) => Promise<void>

데이터를 로드하고 스토어를 업데이트하기 위해 빌드 시점에 호출되는 비동기 함수입니다. 자세한 내용은 LoaderContext를 참조하세요.

타입: ZodSchema | Promise<ZodSchema> | (() => ZodSchema | Promise<ZodSchema>)

항목의 형태를 정의하는 선택적 Zod 스키마입니다. 이는 데이터를 검증하고 컬렉션에 대한 TypeScript 타입을 생성하는 데 사용됩니다.

함수가 제공되는 경우, 스키마를 생성하기 위해 load() 전 빌드 시점에 호출됩니다. 이를 통해 구성 옵션을 기반으로 하거나 API를 검사하여 스키마를 동적으로 생성할 수 있습니다.

이 객체는 로더의 load() 메서드에 전달되며, 다음과 같은 속성들을 포함합니다:

타입: string

컬렉션의 고유한 이름입니다. 이는 src/content.config.ts 파일의 collections 객체에 있는 키입니다.

타입: DataStore

실제 데이터를 저장하는 데이터베이스입니다. 새로운 항목으로 스토어를 업데이트하기 위해 이를 사용하세요. 자세한 내용은 DataStore를 참조하세요.

타입: MetaStore

동기화 토큰이나 마지막 수정 시간과 같은 항목을 위해 설계된 컬렉션 범위의 키-값 저장소입니다. 이 메타데이터는 컬렉션 데이터와 함께 빌드 간 유지되지만 로더에서만 사용할 수 있습니다.

const lastModified = meta.get("lastModified");
// ...
meta.set("lastModified", new Date().toISOString());

타입: AstroIntegrationLogger

콘솔에 메시지를 로깅하는 데 사용할 수 있는 로거입니다. 로그 메시지에 로더 이름을 포함하는 더 유용한 로그를 위해 console.log 대신 이것을 사용하세요. 자세한 내용은 AstroIntegrationLogger를 참조하세요.

타입: AstroConfig

모든 기본값이 적용된 완전히 해결된 Astro 구성 객체입니다. 자세한 내용은 구성 참조를 확인하세요.

타입: (props: ParseDataOptions<TData>) => Promise<TData>

컬렉션 스키마에 따라 데이터를 검증하고 파싱합니다. 데이터 스토어에 저장하기 전에 데이터를 검증하고 파싱하려면 이 함수에 데이터를 전달하세요.

loader.ts
import type { Loader } from "astro/loaders";
import { loadFeed } from "./feed.js";
export function feedLoader({ url }): Loader {
const feedUrl = new URL(url);
return {
name: "feed-loader",
load: async ({ store, logger, parseData, meta, generateDigest }) => {
logger.info("Loading posts");
const feed = loadFeed(feedUrl);
store.clear();
for (const item of feed.items) {
const data = await parseData({
id: item.guid,
data: item,
});
store.set({
id,
data,
});
}
},
};
}

타입: (data: Record<string, unknown> | string) => string

객체나 문자열의 비암호화 콘텐츠 다이제스트를 생성합니다. 이는 항목의 digest 필드를 설정하여 데이터가 변경되었는지 추적하는 데 사용할 수 있습니다.

loader.ts
import type { Loader } from "astro/loaders";
import { loadFeed } from "./feed.js";
export function feedLoader({ url }): Loader {
const feedUrl = new URL(url);
return {
name: "feed-loader",
load: async ({ store, logger, parseData, meta, generateDigest }) => {
logger.info("Loading posts");
const feed = loadFeed(feedUrl);
store.clear();
for (const item of feed.items) {
const data = await parseData({
id: item.guid,
data: item,
});
const digest = generateDigest(data);
store.set({
id,
data,
digest,
});
}
},
};
}

타입: FSWatcher

개발 모드에서 실행 시, 이는 업데이트를 트리거하는 데 사용할 수 있는 파일시스템 감시자입니다. 자세한 내용은 ViteDevServer를 참조하세요.

Extract from the file() loader
return {
name: 'file-loader',
load: async ({ config, store, watcher }) => {
const url = new URL(fileName, config.root);
const filePath = fileURLToPath(url);
await syncData(filePath, store);
watcher?.on('change', async (changedPath) => {
if (changedPath === filePath) {
logger.info(`Reloading data from ${fileName}`);
await syncData(filePath, store);
}
});
},
};

타입: Record<string, unknown>

로더가 통합에 의해 트리거된 경우, 이는 선택적으로 해당 통합에 의해 설정된 추가 데이터를 포함할 수 있습니다. 이는 로더가 통합에 의해 트리거될 때만 설정됩니다. 자세한 내용은 astro:server:setup 훅 참조를 확인하세요.

loader.ts
export function myLoader(options: { url: string }): Loader {
return {
name: "my-loader",
load: async ({ refreshContextData, store, logger }) => {
if(refreshContextData?.webhookBody) {
logger.info("Webhook triggered with body");
processWebhook(store, refreshContextData.webhookBody);
}
// ...
},
};
}

데이터 스토어는 콘텐츠 컬렉션 데이터에 대한 로더의 인터페이스입니다. 이는 컬렉션 범위의 키-값(KV) 스토어이므로, 로더는 자신의 컬렉션에 대한 데이터에만 접근할 수 있습니다.

타입: (key: string) => DataEntry | undefined

스토어에서 ID로 항목을 가져옵니다. 항목이 존재하지 않는 경우 undefined를 반환합니다.

const existingEntry = store.get("my-entry");

DataEntry 객체를 반환합니다.

타입: (entry: DataEntry) => boolean

데이터가 검증되고 파싱된 후에 스토어에 항목을 추가하는 데 사용되며, 항목이 설정되면 true를 반환합니다. digest 속성이 항목이 변경되지 않았으며 업데이트할 필요가 없다고 판단할 때는 false를 반환합니다.

loader.ts
for (const item of feed.items) {
const data = await parseData({
id: item.guid,
data: item,
});
const digest = generateDigest(data);
store.set({
id,
data,
rendered: {
html: data.description ?? "",
},
digest,
});
}

타입: () => Array<[id: string, DataEntry]>

컬렉션의 모든 항목을 키-값 쌍의 배열로 가져옵니다.

타입: () => Array<string>

컬렉션에 있는 항목의 모든 키를 가져옵니다.

타입: () => Array<DataEntry>

컬렉션의 모든 항목을 배열로 가져옵니다.

타입: (key: string) => void

ID를 사용하여 스토어에서 항목을 삭제합니다.

타입: () => void

컬렉션에서 모든 항목을 삭제합니다.

타입: (key: string) => boolean

ID로 항목이 스토어에 존재하는지 확인합니다.

데이터 스토어에 저장되는 객체의 타입입니다. 다음과 같은 속성을 가집니다:

타입: string

컬렉션에서 고유해야 하는 항목의 식별자입니다. 이는 스토어에서 항목을 찾는 데 사용되며 해당 컬렉션에서 getEntry와 함께 사용되는 키입니다.

타입: Record<string, unknown>

항목의 실제 데이터입니다. 사용자가 컬렉션에 접근할 때, 이는 컬렉션 스키마에 따라 생성된 TypeScript 타입을 가지게 됩니다.

데이터 스토어에 저장하기 전에 parseData를 사용하여 데이터를 검증하고 파싱하는 것은 로더의 책임입니다: 데이터를 가져오거나 설정할 때는 검증이 수행되지 않습니다.

타입: string | undefined

이 항목의 소스가 되는 파일의 경로로, 사이트의 루트를 기준으로 합니다. 이는 파일 기반 로더에만 적용되며 이미지나 다른 자산과 같은 경로를 해결하는 데 사용됩니다.

설정되지 않은 경우, image() 헬퍼를 사용하는 스키마의 모든 필드는 공개 경로로 처리되며 변환되지 않습니다.

타입: string | undefined

해당되는 경우 항목의 원본 본문입니다. 항목이 렌더링된 콘텐츠를 포함하는 경우, 이 필드는 원본 소스를 저장하는 데 사용될 수 있습니다. 이는 선택사항이며 내부적으로 사용되지 않습니다.

타입: string | undefined

항목의 선택적 콘텐츠 다이제스트입니다. 이는 데이터가 변경되었는지 확인하는 데 사용될 수 있습니다.

항목을 설정할 때, 다이제스트가 동일한 ID를 가진 기존 항목과 일치하지 않는 경우에만 항목이 업데이트됩니다.

다이제스트의 형식은 로더에 따라 다르지만, 데이터가 변경될 때 변경되는 문자열이어야 합니다. 이는 generateDigest 함수를 사용하여 수행할 수 있습니다.

타입: RenderedContent | undefined

항목이 HTML로 렌더링된 경우 렌더링된 콘텐츠와 메타데이터가 있는 객체를 저장합니다. 예를 들어, 이는 Markdown 항목의 렌더링된 콘텐츠나 CMS의 HTML을 저장하는 데 사용될 수 있습니다.

이 필드가 제공되면, 페이지에서 항목을 렌더링하기 위해 render() 함수와 <Content /> 컴포넌트를 사용할 수 있습니다.

RenderedContent 객체의 형식은 다음과 같습니다:

{
/** 렌더링된 HTML 문자열입니다. 존재하는 경우 `render(entry)`는 이 HTML을 렌더링하는 컴포넌트를 반환합니다. */
html: string;
metadata?: {
/** 이 항목에 존재하는 모든 이미지입니다. {@link DataEntry} filePath를 기준으로 합니다. */
imagePaths?: Array<string>;
/** 이 파일에 존재하는 모든 제목입니다. `render()`에서 `headings`로 반환됩니다 */
headings?: MarkdownHeading[];
/** 파일에서 파싱된 원본 프런트매터입니다. 이는 remark 플러그인의 데이터를 포함할 수 있습니다. */
frontmatter?: Record<string, any>;
/** 이 파일에 존재하는 다른 모든 메타데이터입니다. */
[key: string]: unknown;
};
}
기여하기 커뮤니티 후원하기