콘텐츠로 이동

Astro 콘텐츠 로더 API

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

이 API에는 로컬에 저장된 콘텐츠를 위한 두 가지 즉시 사용 가능한 로더가 포함되어 있습니다. 또한 모든 소스에서 콘텐츠 컬렉션으로 데이터를 로드할 수 있는 고유한 사용자 정의 객체를 구축하기 위한 도구도 제공합니다.

콘텐츠 컬렉션 가이드에서 안내된 설명과 예시 사용법을 통해 빌드 타임 로더에서 로드된 데이터 쿼리 또는 라이브 로더의 라이브 데이터 액세스에 대해 자세히 알아보세요.

빌드 타임 로더는 빌드 시점에 데이터를 가져오고 데이터 저장소를 업데이트하기 위해 호출되는 load() 메서드를 가진 객체입니다. 이 객체는 엔트리에 대한 스키마를 정의할 수도 있으며, 이는 데이터를 검증하고 정적 타입을 생성하는 데 사용될 수 있습니다.

Astro의 glob()file() 로더는 로컬 콘텐츠와 함께 사용하도록 기본적으로 제공되는 객체 로더의 예입니다. 원격 콘텐츠의 경우 사전 빌드된 로더가 제공되지 않습니다. 원격 콘텐츠를 검색하고 데이터 저장소와 상호작용하려면 직접 객체 로더를 빌드하거나 커뮤니티에서 게시한 로더를 사용해야 합니다.

단순한 데이터 가져오기의 경우, 엔트리를 포함하는 배열이나 객체를 반환하는 비동기 함수로 로더를 정의할 수도 있습니다.

타입: (options: GlobOptions) => Loader

추가된 버전: astro@5.0.0

glob() 로더는 파일 시스템의 모든 위치에 있는 파일 디렉터리에서 엔트리를 생성합니다. 지원되는 파일 형식은 Markdown, MDX, Markdoc, JSON, YAML, TOML 파일입니다.

이 로더는 pattern, base (선택 사항), generateId (선택 사항), retainBody (선택 사항) 속성을 가진 객체를 인자로 받습니다.

src/content.config.ts
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';
const pages = defineCollection({
/* pages 디렉터리의 모든 Markdown 파일을 검색합니다. */
loader: glob({ pattern: "**/*.md", base: "./src/data/pages" }),
});
const blog = defineCollection({
/* blog 디렉터리의 모든 Markdown 및 MDX 파일을 검색합니다. */
loader: glob({ pattern: "**/*.(md|mdx)", base: "./src/data/blog" }),
});
const notes = defineCollection({
/* notes 디렉터리의 모든 Markdown 파일을 검색하고
* 콘텐츠 파일의 원본 본문이 데이터 저장소에 저장되지 않도록 방지합니다. */
loader: glob({
pattern: '**/*.md',
base: './src/data/notes',
retainBody: false
}),
});
const authors = defineCollection({
/* authors 디렉터리의 모든 JSON 파일을 검색하면서
* ID의 대문자를 그대로 유지합니다. */
loader: glob({
pattern: '**/*.json',
base: "./src/data/authors",
generateId: ({ entry }) => entry.replace(/\.json$/, ''),
}),
});
export const collections = { pages, blog, authors };

타입: string | string[]

pattern 속성은 glob 일치(예: 와일드카드, globstars)를 사용하는 문자열 또는 문자열 배열을 허용합니다. 패턴은 일치시킬 엔트리 파일의 기준 디렉터리에 대한 상대 경로여야 합니다.

사용할 구문에 대한 자세한 내용은 micromatch 문서에서 확인할 수 있습니다. 또한 DigitalOcean Glob 도구와 같은 온라인 도구를 사용하여 패턴의 유효성을 확인할 수 있습니다.

타입: string | URL
기본값: "."

pattern을 해석할 기준 디렉터리에 대한 상대 경로 또는 URL입니다.

타입: (options: GenerateIdOptions) => string

컬렉션의 각 엔트리에 대해 고유한 문자열을 반환하는 콜백 함수입니다. 다음 속성을 포함하는 객체를 매개변수로 받습니다:

  • entry - 기준 디렉터리에 대한 엔트리 파일의 경로
  • base - 기준 디렉터리 URL
  • data - 파싱되었으나 아직 검증되지 않은 엔트리 데이터

기본적으로 github-slugger를 사용하여 kebab-case 단어로 슬러그를 생성합니다.

타입: boolean
기본값: true

추가된 버전: astro@5.17.0

콘텐츠 파일의 원본 본문(body)을 데이터 저장소에 저장할지 여부입니다.

retainBodyfalse인 경우, entry.body는 원본 파일 내용을 포함하는 대신 undefined가 됩니다.

이 속성을 false로 설정하면 배포된 데이터 저장소의 크기가 크게 줄어들어 매우 큰 컬렉션이 있는 사이트에서 크기 제한에 걸리는 것을 방지하는 데 도움이 됩니다.

Markdown 파일의 경우 렌더링된 본문은 여전히 entry.rendered.html 속성에서 사용할 수 있으며, entry.filePath 속성은 여전히 원본 파일을 가리킵니다.

MDX 컬렉션의 경우 저장소에 더 이상 본문이 보존되지 않으므로 컬렉션 크기가 크게 줄어듭니다.

타입: (fileName: string, options?: FileOptions) => Loader

추가된 버전: astro@5.0.0

file() 로더는 고유한 id 필드를 가진 객체 배열이나 ID를 키로 하고 엔트리를 값으로 하는 객체를 포함하는 단일 파일에서 엔트리를 생성합니다.

JSON, YAML, TOML 파일을 지원하며, 기본적으로 파싱할 수 없는 데이터 파일을 위한 사용자 정의 parser를 제공하거나 데이터를 비동기적으로 파싱할 수 있습니다.

이 로더는 fileName 속성과 두 번째 인자로 선택적인 옵션 객체를 받습니다:

src/content.config.ts
import { defineCollection } from 'astro:content';
import { file } from 'astro/loaders';
const authors = defineCollection({
/* JSON 파일에서 모든 엔트리를 가져옵니다. */
loader: file("src/data/authors.json"),
});
const products = defineCollection({
/* 사용자 정의 파서를 사용하여 CSV 파일에서 모든 엔트리를 가져옵니다. */
loader: file("src/data/products.csv", {
parser: (fileContent) => { /* 파서 로직 */ },
}),
});
export const collections = { authors, products };

타입: string

로드할 파일의 경로를 루트 디렉터리에 대한 상대 경로로 설정합니다.

타입: FileOptions

다음 속성을 포함하는 선택적 객체입니다:

타입: (text: string) => Record<string, Record<string, unknown>> | Array<Record<string, unknown>> | Promise<Record<string, Record<string, unknown>> | Array<Record<string, unknown>>>

파일 내용으로부터 컬렉션을 생성하는 콜백 함수입니다. 기본적으로 지원되지 않는 파일(예: .csv)을 처리해야 하거나 중첩된 .json 문서를 사용할 때 사용합니다.

콘텐츠 로더 API는 유연하고 모든 기능을 갖추고 있어 다양한 데이터 가져오기 옵션이 가능합니다. 간단한 로더와 복잡한 로더를 모두 빌드할 수 있습니다. 사용자 정의 로더는 데이터의 소스와 형태, 그리고 영구 데이터 저장 레이어를 관리하는 방식에 따라 달라집니다.

대부분의 로더는 구성 옵션을 수락하고 로더의 name, load() 메서드, 엔트리를 정의하는 schema를 포함하는 로더 객체를 반환하는 함수를 내보냅니다.

데이터 저장소로 컬렉션 로드하기

섹션 제목: “데이터 저장소로 컬렉션 로드하기”

로더 객체에서 반환되는 load() 함수는 콘텐츠를 가져오고, 파싱하고, 검증하고, 업데이트하는 방법을 정의합니다. 이 함수는 다양한 방식으로 데이터 처리를 사용자 정의하고 데이터 저장소와 상호작용할 수 있게 해주는 context 객체를 받습니다. 일반적인 load() 함수는 다음과 같은 작업을 수행합니다:

  • 소스에서 데이터를 가져옵니다.
  • 기존 데이터 저장소를 비웁니다.
  • 제공된 스키마에 따라 데이터 엔트리를 파싱하고 검증합니다.
  • 새로운 엔트리로 데이터 저장소를 업데이트합니다.

또한 load() 메서드는 콘솔에 메시지를 로깅하고, 콘텐츠를 HTML로 렌더링하고, 개발 모드에서 변경 사항을 감시하여 데이터를 다시 로드하고, 메타데이터 및 전체 Astro 설정에 대한 액세스를 제공하는 등의 헬퍼를 제공합니다.

load() 함수에서 사용할 수 있는 모든 옵션은 LoaderContext 속성 목록을 참조하세요.

로더에 Zod schema를 제공하면 가져온 콘텐츠 엔트리를 데이터 저장소에 추가하기 전에 parseData()로 검증할 수 있습니다. 이 스키마는 타입 안전성과 에디터 도구를 제공하기 위해 src/content.config.ts에 스키마가 존재하지 않을 때 컬렉션의 기본 스키마로도 사용됩니다. 로더가 이 속성을 제공하는 경우 콘텐츠 컬렉션에 스키마를 정의할 필요가 없습니다.

그러나 콘텐츠 컬렉션에서도 스키마를 정의하는 경우, 해당 스키마가 로더의 스키마 대신 사용됩니다. 이는 로더 사용자가 스키마를 확장하거나 프로젝트에서 사용할 데이터를 변형할 수 있도록 하기 위함입니다. 다른 사람들이 사용할 수 있도록 로더를 게시하고 배포하는 경우, 이 동작을 문서화하고 사용자가 컬렉션 스키마를 직접 정의하지 않도록 권장하거나, 다른 형식으로 데이터를 반환받아야 할 때 안전하게 정의하는 방법을 안내하는 것이 좋습니다.

구성 옵션이나 API 검사를 바탕으로 스키마를 동적으로 생성해야 하는 경우에는 대신 createSchema()를 사용할 수 있습니다.

다음 예시는 제공된 피드 URL에서 데이터를 가져오고(사용자 정의 loadFeedData 유틸리티 사용), 사이트가 빌드될 때마다 새로운 엔트리로 데이터 저장소를 업데이트하는 로더를 보여줍니다:

src/feed-loader.ts
// 1. `Loader` 타입 및 필요한 기타 의존성 가져오기
import type { Loader } from 'astro:loaders';
import { z } from 'astro:zod';
import { loadFeedData } from "./feed.js";
// 2. 로더에 필요한 옵션 정의
export function feedLoader(options: { url: string, apiKey: string }) {
const feedUrl = new URL(options.url);
// 3. 로더 객체 반환
return {
name: "feed-loader",
load: async ({ store, parseData }) => {
const feed = await loadFeedData(feedUrl, options.apiKey);
store.clear();
for (const item of feed.items) {
const id = item.guid;
const data = await parseData({
id,
data: item,
});
store.set({
id,
data,
});
}
},
// 4. 엔트리의 스키마 정의
schema: z.object({
// ...
})
} satisfies Loader;
}

로더를 사용하여 컬렉션 정의하기

섹션 제목: “로더를 사용하여 컬렉션 정의하기”

src/content.config.ts에서 컬렉션을 정의할 때 사용자 정의 로더를 loader 속성의 값으로 사용하세요. 구성 옵션은 인자로 로더에 전달할 수 있습니다.

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

사용자 정의 데이터 저장소 처리, 검증, 로깅 또는 빌드 타임 로더 객체에서 제공하는 기타 헬퍼가 필요 없는 단순한 데이터 가져오기의 경우, 로더를 함수로 정의할 수 있습니다.

함수는 비동기일 수 있으며, 각각 고유한 id 필드를 포함하는 엔트리 배열이나 각 키가 고유 ID이고 각 값이 엔트리인 객체를 반환해야 합니다.

이 패턴은 컬렉션을 데이터 저장소에 로드하기 위해 load() 함수가 수행하는 기본 작업을 편리하게 수행할 수 있는 약칭을 제공합니다. 빌드 시점에 로더는 자동으로 데이터 저장소를 비우고 모든 엔트리를 다시 로드합니다. 데이터 처리를 위한 추가적인 사용자 정의 옵션이나 헬퍼는 제공되지 않습니다.

이러한 로더는 src/content.config.ts 파일 내에 인라인으로 정의할 수 있을 만큼 간단합니다:

src/content.config.ts
import { defineCollection } from "astro:content";
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,
}));
},
});
export const collections = { countries };

라이브 로더 API는 실시간으로 모든 데이터를 쿼리하도록 빌드되었습니다. 라이브 로더는 들어오는 데이터를 필터링하고 타입 안전성을 통해 콘텐츠를 확인할 수 있습니다. 라이브 로더는 모든 요청에 대해 새로운 데이터를 가져오므로 업데이트할 데이터 저장소가 없습니다. 이 로더는 에러를 우아하게 처리할 수 있도록 데이터 또는 Error 객체를 반환하도록 설계되었습니다.

대부분의 라이브 로더는 구성 옵션을 수락하고 로더의 name과 엔트리 컬렉션을 로드하는 방법 및 단일 엔트리를 로드하는 방법을 정의하는 두 가지 메서드인 loadCollection()loadEntry()를 포함하는 라이브 로더 객체를 반환하는 함수를 내보냅니다.

컬렉션에 대한 데이터를 반환하려면 데이터를 가져와 콘텐츠 entries 배열 또는 에러를 반환하는 loadCollection() 함수를 제공해야 합니다.

단일 라이브 컬렉션 엔트리를 반환하려면 지정된 id로 필터링된 데이터를 가져와 단일 entry, undefined 또는 에러를 반환하는 loadEntry() 함수를 제공해야 합니다.

이 두 함수에 대한 데이터 가져오기는 일반적으로 라이브 데이터 액세스 시 에러를 처리하기 위해 try...catch을 사용하여 수행됩니다.

라이브 로더 빌드에 사용할 수 있는 함수와 타입에 대한 자세한 내용은 전체 라이브 로더 API를 참조하세요.

라이브 로더를 위한 스키마 제공하기

섹션 제목: “라이브 로더를 위한 스키마 제공하기”

라이브 로더는 스키마 속성을 포함하지 않습니다. 대신 src/live.config.ts에서 컬렉션에 대한 Zod 스키마를 정의하거나 반환하는 데이터에 대해 LiveLoader 인터페이스에 제네릭 타입을 전달하여 타입 안전성을 제공할 수 있습니다.

다음 예시는 CMS에서 데이터 가져오기(사용자 정의 fetchFromCMS 유틸리티 사용)를 정의하는 라이브 로더를 보여줍니다. 타입 안전성 및 에러 처리를 포함하여 엔트리 컬렉션과 단일 엔트리 모두에 대해 수행됩니다:

src/article-loader.ts
import type { LiveLoader } from 'astro:loaders';
import { fetchFromCMS } from './cms-client.js';
interface Article {
id: string;
title: string;
htmlContent: string;
author: string;
}
interface EntryFilter {
id: string;
}
interface CollectionFilter {
author?: string;
}
export function articleLoader(config: { apiKey: string }): LiveLoader<Article, EntryFilter, CollectionFilter> {
return {
name: 'article-loader',
loadCollection: async ({ filter }) => {
try {
const articles = await fetchFromCMS({
apiKey: config.apiKey,
type: 'article',
filter,
});
return {
entries: articles.map((article) => ({
id: article.id,
data: article,
})),
};
} catch (error) {
return {
error: new Error('Failed to load articles', { cause: error }),
};
}
},
loadEntry: async ({ filter }) => {
try {
// 문자열로 호출될 때 filter는 { id: "some-id" }가 됩니다.
const article = await fetchFromCMS({
apiKey: config.apiKey,
type: 'article',
id: filter.id,
});
if (!article) {
return {
error: new Error('Article not found'),
};
}
return {
id: article.id,
data: article,
rendered: {
html: article.htmlContent,
},
};
} catch (error) {
return {
error: new Error('Failed to load article', { cause: error }),
};
}
},
};
}

로더를 사용하여 라이브 컬렉션 정의하기

섹션 제목: “로더를 사용하여 라이브 컬렉션 정의하기”

src/live.config.ts에서 컬렉션을 정의할 때 사용자 정의 라이브 로더를 loader 속성의 값으로 사용하세요. 구성 옵션은 인자로 로더에 전달할 수 있습니다.

src/live.config.ts
import { defineLiveCollection } from 'astro:content';
import { articleLoader } from './article-loader.ts';
const blog = defineLiveCollection({
loader: articleLoader({
apiKey: "my-secret",
}),
});
export const collections = { blog };

라이브 로더는 에러 발생 시 Error 서브클래스를 반환합니다. 필요한 경우 더 구체적인 에러 처리를 위해 사용자 정의 에러 타입을 만들어 사용할 수 있습니다. 라이브 로더에서 에러가 발생(throw)하면 Astro가 이를 잡아 LiveCollectionError로 감싸서 반환합니다.

Astro는 라이브 로더의 응답에 따라 자체적으로 몇 가지 에러를 생성합니다:

  • loadEntryundefined를 반환하면 Astro는 사용자에게 LiveEntryNotFoundError를 반환합니다.
  • 컬렉션에 스키마가 정의되어 있고 데이터가 스키마와 일치하지 않으면 Astro는 LiveCollectionValidationError를 반환합니다.
  • 로더가 유효하지 않은 캐시 힌트를 반환하면 Astro는 LiveCollectionCacheHintError를 반환합니다. cacheHint 필드는 선택 사항이므로 반환할 유효한 데이터가 없는 경우 간단히 생략할 수 있습니다.
my-loader.ts
import type { LiveLoader } from 'astro:loaders';
import type { MyData } from "./types";
import { MyLoaderError } from './errors';
export function myLoader(config): LiveLoader<MyData, never, never, MyLoaderError> {
return {
name: 'my-loader',
loadCollection: async () => {
// 사용자 정의 에러 타입 반환
return {
error: new MyLoaderError('Failed to load', 'LOAD_ERROR'),
};
},
// ...
};
}

로더에서 반환되는 에러를 위해 사용자 정의 에러 타입을 만들고, 적절한 타이핑을 얻기 위해 제네릭으로 전달할 수 있습니다:

my-loader.ts
import type { LiveLoader } from "astro:loaders";
import type { MyData } from "./types"
export class MyLoaderError extends Error {
constructor(message: string, public code?: string) {
super(message);
this.name = 'MyLoaderError';
}
}
export function myLoader(config): LiveLoader<MyData, never, never, MyLoaderError> {
return {
name: 'my-loader',
loadCollection: async () => {
// 사용자 정의 에러 타입 반환
return {
error: new MyLoaderError('Failed to load', 'LOAD_ERROR'),
};
},
// ...
};
}

getLiveCollection() 또는 getLiveEntry()를 사용할 때 TypeScript는 사용자 정의 에러 타입을 유추하므로 이를 적절하게 처리할 수 있습니다:

---
export const prerender = false; // 'server' 모드에서는 필요 없음
import { getLiveEntry } from 'astro:content';
import { MyLoaderError } from "../my-loader";
const { entry, error } = await getLiveEntry('products', '123');
if (error) {
if (error instanceof MyLoaderError) {
console.error(`Loader error: ${error.message} (code: ${error.code})`);
} else {
console.error(`Unexpected error: ${error.message}`);
}
return Astro.rewrite('/500');
}
---

사용자 정의 필터 타입 정의하기

섹션 제목: “사용자 정의 필터 타입 정의하기”

라이브 로더는 getLiveCollection()getLiveEntry() 모두에 대해 사용자 정의 필터 타입을 정의할 수 있습니다. 이를 통해 API의 기능과 일치하는 타입 안전 쿼리가 가능해지며, 사용자가 사용 가능한 필터를 더 쉽게 검색하고 올바르게 사용할 수 있도록 도와줍니다. 필터 타입에 JSDoc 주석을 포함하면 사용자는 로더를 사용할 때 IDE에서 이를 힌트로 볼 수 있습니다.

store-loader.ts
import type { LiveLoader } from 'astro:loaders';
import { fetchProduct, fetchCategory, type Product } from './store-client';
interface CollectionFilter {
category?: string;
/** 제품 필터링을 위한 최소 가격 */
minPrice?: number;
/** 제품 필터링을 위한 최대 가격 */
maxPrice?: number;
}
interface EntryFilter {
/** `sku`의 별칭 */
id?: string;
slug?: string;
sku?: string;
}
export function productLoader(config: {
apiKey: string;
endpoint: string;
}): LiveLoader<Product, EntryFilter, CollectionFilter> {
return {
name: 'product-loader',
loadCollection: async ({ filter }) => {
// filter는 CollectionFilter로 타입이 지정됩니다.
const data = await fetchCategory({
apiKey: config.apiKey,
category: filter?.category ?? 'all',
minPrice: filter?.minPrice,
maxPrice: filter?.maxPrice,
});
return {
entries: data.products.map((product) => ({
id: product.sku,
data: product,
})),
};
},
loadEntry: async ({ filter }) => {
// filter는 EntryFilter | { id: string }으로 타입이 지정됩니다.
const product = await fetchProduct({
apiKey: config.apiKey,
slug: filter.slug,
sku: filter.sku || filter.id,
});
if (!product) {
return {
error: new Error('Product not found'),
};
}
return {
id: product.sku,
data: product,
};
},
};
}

라이브 로더는 응답 캐싱을 돕기 위해 캐시 힌트를 제공할 수 있습니다. 이 데이터를 사용하여 HTTP 캐시 헤더를 보내거나 캐싱 전략에 정보를 제공할 수 있습니다.

my-loader.ts
import type { LiveLoader } from "astro:loaders";
import { loadStoreProduct, loadStoreProducts, getLastModifiedDate } from "./store";
import type { Product, ProductEntryFilter, ProductCollectionFilter } from "./types";
export function myLoader(config): LiveLoader<Product, ProductEntryFilter, ProductCollectionFilter> {
return {
name: 'cached-loader',
loadCollection: async ({ filter }) => {
const products = await loadStoreProducts(filter);
return {
entries: products.map((item) => ({
id: item.id,
data: item,
// 각 엔트리에 대해 선택적으로 캐시 힌트를 제공할 수 있습니다.
cacheHint: {
tags: [`product-${item.id}`, `category-${item.category}`],
},
})),
cacheHint: {
// 모든 필드는 선택 사항이며 각 엔트리의 캐시 힌트와 결합됩니다.
// tags는 모든 엔트리에서 병합됩니다.
// lastModified는 모든 엔트리와 컬렉션 중 가장 최근의 lastModified입니다.
lastModified: getLastModifiedDate(products),
tags: ['products'],
},
};
},
loadEntry: async ({ filter }) => {
const item = await loadStoreProduct(filter);
return {
id: item.id,
data: item,
cacheHint: {
lastModified: new Date(item.lastModified),
tags: [`product-${item.id}`, `category-${item.category}`],
},
};
},
};
}

그런 다음 페이지에서 이러한 힌트를 사용할 수 있습니다. 실험적 라우트 캐싱 (EN)이 활성화된 경우 캐시 힌트를 Astro.cache.set()에 직접 전달합니다:

src/pages/store/[id].astro
---
export const prerender = false; // 'server' 모드에서는 필요 없음
import { getLiveEntry } from 'astro:content';
const { entry, error, cacheHint } = await getLiveEntry('products', Astro.params.id);
if (error) {
return Astro.redirect('/404');
}
// 라우트 캐싱에 캐시 힌트 전달
if (cacheHint) {
Astro.cache.set(cacheHint);
}
Astro.cache.set({ maxAge: 300 });
---
<h1>{entry.data.name}</h1>
<p>{entry.data.description}</p>

라우트 캐싱이 활성화되지 않은 경우, 고유한 캐싱 전략에 따라 응답 헤더를 수동으로 설정하는 데 캐시 힌트를 사용할 수 있습니다:

src/pages/store/[id].astro
---
export const prerender = false; // 'server' 모드에서는 필요 없음
import { getLiveEntry } from 'astro:content';
const { entry, error, cacheHint } = await getLiveEntry('products', Astro.params.id);
if (error) {
return Astro.redirect('/404');
}
if (cacheHint?.tags) {
Astro.response.headers.set('Cache-Tag', cacheHint.tags.join(','));
}
if (cacheHint?.lastModified) {
Astro.response.headers.set('Last-Modified', cacheHint.lastModified.toUTCString());
}
---
<h1>{entry.data.name}</h1>
<p>{entry.data.description}</p>

로더는 사이트 내에 정의하거나 별도의 npm 패키지로 정의할 수 있습니다. 로더를 커뮤니티와 공유하고 싶다면 withastroastro-loader 키워드를 사용하여 npm에 게시할 수 있습니다.

로더는 라이브 로더의 경우 LiveLoader 객체를, 빌드 타임 로더의 경우 Loader 객체를 반환하는 함수를 내보내어 사용자가 자체 설정으로 구성할 수 있도록 해야 합니다.

추가된 버전: astro@5.0.0

이 섹션에서는 빌드 타임 객체 로더를 정의하기 위한 API를 보여줍니다.

타입: Loader

로더 함수는 두 가지 필수 속성을 가진 객체를 반환합니다. 로더의 이름을 제공하는 것 외에도 이 객체는 컬렉션 데이터를 가져오는 방법을 설명합니다.

선택적으로, 컬렉션 엔트리를 검증하기 위한 스키마를 정의하는 세 번째 속성을 반환할 수 있습니다. 로더 객체 내부에서 타입 안전성을 제공하고 로더가 컬렉션에서 사용될 때 타입 추론을 유지하려면 반환 타입 어노테이션 대신 Typescript satisfies 연산자를 사용하세요.

타입: string

추가된 버전: astro@5.0.0

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

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

추가된 버전: astro@5.0.0

빌드 시점에 데이터를 로드하고 저장소를 업데이트하기 위해 호출되는 비동기 함수입니다. 로더의 구현 로직 작성을 위한 헬퍼 함수와 속성, 그리고 store 데이터베이스 및 이와 상호작용하기 위한 메서드를 포함하는 LoaderContext 객체가 전달됩니다.

타입: ZodSchema

추가된 버전: astro@5.0.0

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

구성 옵션이나 API 검사를 바탕으로 빌드 시점에 스키마를 동적으로 생성해야 하는 경우에는 대신 createSchema()를 사용하세요.

이 속성이 존재하는 경우, src/content.config.ts 파일의 컬렉션에 정의된 Zod schema에 의해 재정의됩니다.

타입: () => Promise<{ schema: ZodSchema; types: string }>

추가된 버전: astro@6.0.0 새로운 기능

Zod 스키마와 타입을 포함하는 객체를 반환하는 선택적인 비동기 함수입니다. 구성 옵션이나 API 검사를 바탕으로 빌드 시점에 스키마를 동적으로 생성하는 데 사용됩니다.

정적 스키마만 제공하면 되는 경우에는 대신 schema를 사용하여 Zod 검증 객체를 제공하세요.

이 속성이 존재하는 경우, src/content.config.ts 파일의 컬렉션에 정의된 Zod schema에 의해 재정의됩니다.

반환된 types 내용은 TypeScript 파일에 기록되며, 반드시 Entry 타입 또는 인터페이스를 내보내야 합니다:

src/feed-loader.ts
import type { Loader } from 'astro:loaders';
import { z } from 'astro:zod';
import { loadFeedData, getSchema, getTypes } from "./feed.js";
export function myLoader(options: { url: string, apiKey: string }) {
const feedUrl = new URL(options.url);
return {
name: "feed-loader",
load: async ({ store, parseData }) => {
const feed = await loadFeedData(feedUrl, options.apiKey);
store.clear();
for (const item of feed.items) {
const id = item.guid;
const data = await parseData({
id,
data: item,
});
store.set({
id,
data,
});
}
},
createSchema: async () => {
const schema = await getSchema();
const types = await getTypes();
return {
schema,
types: `export type Entry = ${types}`,
};
},
} satisfies Loader;
}

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

타입: string

추가된 버전: astro@5.0.0

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

타입: DataStore

추가된 버전: astro@5.0.0

실제 데이터를 저장하기 위한 데이터베이스입니다. 새로운 엔트리로 저장소를 업데이트하는 데 사용합니다. 자세한 내용은 DataStore를 참조하세요.

타입: MetaStore

추가된 버전: astro@5.0.0

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

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

타입: AstroIntegrationLogger

추가된 버전: astro@5.0.0

콘솔에 메시지를 로깅하는 데 사용할 수 있는 로거입니다. console.log 대신 이를 사용하면 로그 메시지에 로더 이름이나 로딩 프로세스에 대한 정보와 같은 로더 관련 콘텐츠가 포함되어 더 유용한 로그를 제공할 수 있습니다. 자세한 내용은 AstroIntegrationLogger를 참조하세요.

file() 로더의 추출 예시
return {
name: 'file-loader',
load: async ({ config, store, logger, 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);
}
});
},
};

타입: AstroConfig

추가된 버전: astro@5.0.0

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

file() 로더의 추출 예시
return {
name: 'file-loader',
load: async ({ config, store, logger, 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);
}
});
},
};

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

추가된 버전: astro@5.0.0

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

loader.ts
import type { Loader } from "astro/loaders";
import { loadFeed } from "./feed.js";
export function feedLoader({ url }) {
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 id = item.guid;
const data = await parseData({
id,
data: item,
});
store.set({
id,
data,
});
}
},
} satisfies Loader;
}

타입: (content: string, options?: { fileURL?: URL }) => Promise<RenderedContent>

추가된 버전: astro@5.9.0

Markdown 문자열을 HTML로 렌더링하여 RenderedContent 객체를 반환합니다.

이를 통해 Astro의 내장 glob() 로더와 동일한 Markdown 처리를 사용하여 로더 내에서 직접 Markdown 콘텐츠를 렌더링할 수 있으며, 본문 콘텐츠 렌더링을 위한 render() 함수 및 <Content /> 컴포넌트에 대한 액세스를 제공합니다.

사용자가 페이지에서 콘텐츠를 렌더링할 수 있도록 이 객체를 DataEntry 객체의 rendered 필드에 할당하세요. Markdown 콘텐츠에 프론트매터가 포함된 경우 파싱되어 metadata.frontmatter에서 사용할 수 있습니다. 프론트매터는 HTML 출력에서 제외됩니다.

loader.ts
import type { Loader } from 'astro:loaders';
import { loadFromCMS } from './cms.js';
export function myLoader(settings) {
return {
name: 'cms-loader',
async load({ renderMarkdown, store }) {
const entries = await loadFromCMS();
store.clear();
for (const entry of entries) {
store.set({
id: entry.id,
data: entry,
// 각 엔트리에 Markdown 콘텐츠가 포함된 'content' 필드가 있다고 가정합니다.
rendered: await renderMarkdown(entry.content),
});
}
},
} satisfies Loader;
}

타입: URL

추가된 버전: astro@6.0.0 새로운 기능

Markdown 콘텐츠에서 상대 이미지 경로를 해석하는 데 사용할 파일 경로를 지정합니다.

다음 예시는 구성된 루트 디렉터리를 사용하여 이미지 경로를 해석합니다:

loader.ts
for (const file of files) {
const content = await readFile(file.path, 'utf8');
store.set({
id: file.id,
data: file.data,
rendered: await renderMarkdown(content, {
fileURL: new URL(file.path, config.root),
}),
});
}

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

추가된 버전: astro@5.0.0

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

loader.ts
import type { Loader } from "astro:loaders";
import { loadFeed } from "./feed.js";
export function feedLoader({ url }) {
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 id = item.guid;
const data = await parseData({
id,
data: item,
});
const digest = generateDigest(data);
store.set({
id,
data,
digest,
});
}
},
} satisfies Loader;
}

타입: FSWatcher

추가된 버전: astro@5.0.0

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

file() 로더의 추출 예시
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@5.0.0

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

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

데이터 저장소는 로더가 콘텐츠 컬렉션 데이터에 접근하는 인터페이스입니다. 컬렉션에 한정된 키-값(KV) 저장소이므로 로더는 고유한 컬렉션의 데이터에만 액세스할 수 있습니다.

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

추가된 버전: astro@5.0.0

ID로 저장소에서 엔트리를 가져옵니다. 엔트리가 존재하지 않으면 undefined를 반환합니다.

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

반환된 객체는 DataEntry 객체입니다.

타입: (entry: DataEntry) => boolean

추가된 버전: astro@5.0.0

데이터가 검증 및 파싱된 후 저장소에 엔트리를 추가하는 데 사용되며, 엔트리가 설정되면 true를 반환합니다. digest 속성에 따라 엔트리가 변경되지 않았으며 업데이트되지 않아야 한다고 판단되면 false를 반환합니다.

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

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

추가된 버전: astro@5.0.0

컬렉션의 모든 엔트리를 키-값 쌍의 배열로 가져옵니다.

타입: () => Array<string>

추가된 버전: astro@5.0.0

컬렉션에 있는 엔트리의 모든 키를 가져옵니다.

타입: () => Array<DataEntry>

추가된 버전: astro@5.0.0

컬렉션의 모든 엔트리를 배열로 가져옵니다.

타입: (key: string) => void

추가된 버전: astro@5.0.0

ID로 저장소에서 엔트리를 삭제합니다.

타입: () => void

추가된 버전: astro@5.0.0

컬렉션의 모든 엔트리를 삭제합니다.

타입: (key: string) => boolean

추가된 버전: astro@5.0.0

ID로 저장소에 엔트리가 존재하는지 확인합니다.

데이터 저장소에 저장되는 객체의 타입입니다. 다음 속성을 가집니다:

타입: string

추가된 버전: astro@5.0.0

컬렉션 내에서 고유해야 하는 엔트리 식별자입니다. 이는 저장소에서 엔트리를 찾는 데 사용되며, 해당 컬렉션에 대해 getEntry()와 함께 사용되는 키입니다.

타입: Record<string, unknown>

추가된 버전: astro@5.0.0

엔트리의 실제 데이터입니다. 사용자가 컬렉션에 액세스할 때, 이는 컬렉션 스키마에 따라 생성된 TypeScript 타입을 갖게 됩니다.

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

타입: string | undefined

추가된 버전: astro@5.0.0

이 엔트리의 소스 파일 경로로, 사이트 루트에 대한 상대 경로입니다. 이는 파일 기반 로더에만 적용되며 이미지나 기타 자산과 같은 경로를 해석하는 데 사용됩니다.

설정되지 않은 경우, 스키마에서 image() 도우미를 사용하는 모든 필드는 공용 경로로 취급되며 변환되지 않습니다.

타입: string | undefined

추가된 버전: astro@5.0.0

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

타입: string | undefined

추가된 버전: astro@5.0.0

엔트리에 대한 선택적인 콘텐츠 다이제스트입니다. 데이터가 변경되었는지 확인하는 데 사용할 수 있습니다.

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

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

타입: RenderedContent | undefined

추가된 버전: astro@5.0.0

엔트리가 HTML로 렌더링된 경우 엔트리의 렌더링된 콘텐츠 및 메타데이터를 포함하는 객체를 저장합니다. 예를 들어 Markdown 엔트리의 렌더링된 콘텐츠나 CMS의 HTML을 저장하는 데 사용할 수 있습니다.

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

엔트리에 Markdown 콘텐츠가 있는 경우 renderMarkdown() 함수를 사용하여 Markdown 문자열에서 이 객체를 생성할 수 있습니다.

타입: string

렌더링된 HTML 문자열을 포함합니다. 이는 render()에 의해 이 HTML을 렌더링하는 컴포넌트를 반환하는 데 사용됩니다.

타입: object | undefined

이 파일에 존재하는 메타데이터를 설명합니다. 여기에는 imagePaths, headings, frontmatter 및 파일에 존재하는 기타 메타데이터가 포함됩니다. 파일이 HTML로 렌더링되지 않은 경우 이 값은 undefined가 됩니다.

타입: string[]

이 엔트리에 존재하는 이미지 경로 목록을 지정합니다. 각 경로는 엔트리 filePath에 대한 상대 경로입니다.

타입: MarkdownHeading[]

이 파일에 존재하는 헤딩(제목) 목록을 지정합니다. 각 헤딩은 레벨에 의해 결정되는 depth (h1 -> h6), github-slugger로 생성된 slug, 그리고 text 콘텐츠로 설명됩니다.

타입: Record<string, any>

파일에서 파싱된 원본 프론트매터를 설명합니다. 여기에는 remark 플러그인에서 프로그래밍 방식으로 주입된 데이터가 포함될 수 있습니다.

추가된 버전: astro@6.0.0 새로운 기능

이 섹션에서는 라이브 로더를 정의하기 위한 API를 보여줍니다.

타입: LiveLoader<TData, TEntryFilter, TCollectionFilter, TError>

추가된 버전: astro@6.0.0 새로운 기능

라이브 로더 함수는 세 가지 필수 라이브 로더 속성을 가진 객체를 반환합니다. 로더의 이름을 제공하는 것 외에도 이 객체는 라이브 데이터 소스에서 단일 엔트리와 전체 컬렉션을 모두 가져오는 방법을 설명합니다.

로더에서 타입 안전성을 제공하려면 LiveLoader 제네릭 타입을 사용하세요. 이 타입은 순서대로 다음 타입 매개변수를 받습니다:

  • TData (기본값: Record<string, unknown>): 로더에 의해 반환되는 각 엔트리의 데이터 구조입니다.
  • TEntryFilter (기본값: never): getLiveEntry()에서 허용되고 loadEntry()에서 액세스 가능한 필터 객체 타입입니다. 단일 엔트리 필터링을 지원하지 않는 경우 never를 사용하세요.
  • TCollectionFilter (기본값: never): getLiveCollection()에서 허용되고 loadCollection()에서 액세스 가능한 필터 객체 타입입니다. 컬렉션 필터링을 지원하지 않는 경우 never를 사용하세요.
  • TError (기본값: Error): 더 세밀한 에러 처리를 위해 로더에서 반환할 수 있는 사용자 정의 Error 클래스입니다.

타입: string

추가된 버전: astro@6.0.0 새로운 기능

로그에 사용되는 로더의 고유 이름입니다.

타입: (context: LoadCollectionContext<TCollectionFilter>) => Promise<LiveDataCollection<TData> | { error: TError; }>

추가된 버전: astro@6.0.0 새로운 기능

엔트리 컬렉션을 로드하는 메서드를 정의합니다. 이 함수는 선택적인 filter 속성을 포함하는 컨텍스트 객체를 받으며, 이 컬렉션과 관련된 데이터 또는 에러를 반환해야 합니다.

타입: (context: LoadEntryContext<TEntryFilter>) => Promise<LiveDataEntry<TData> | undefined | { error: TError; }>

추가된 버전: astro@6.0.0 새로운 기능

단일 엔트리를 로드하는 메서드를 정의합니다. 이 함수는 filter 속성을 포함하는 컨텍스트 객체를 받으며, 요청된 엔트리와 관련된 데이터, 엔트리를 찾을 수 없는 경우 undefined, 또는 에러를 반환합니다.

타입: { filter?: TCollectionFilter; }

추가된 버전: astro@6.0.0 새로운 기능

이 객체는 로더의 loadCollection() 메서드에 전달되며 다음 속성을 포함합니다:

타입: Record<string, any> | never
기본값: never

추가된 버전: astro@6.0.0 새로운 기능

로더에서 지원하는 필터를 설명하는 객체입니다.

타입: { filter: TEntryFilter; }

추가된 버전: astro@6.0.0 새로운 기능

이 객체는 로더의 loadEntry() 메서드에 전달되며 다음 속성을 포함합니다:

타입: Record<string, any> | never
기본값: never

추가된 버전: astro@6.0.0 새로운 기능

로더에서 지원하는 필터를 설명하는 객체입니다.

타입: { id: string; data: TData; rendered?: { html: string }; cacheHint?: CacheHint; }

추가된 버전: astro@6.0.0 새로운 기능

loadEntry() 메서드에 의해 반환되는 객체 타입입니다. 다음 속성을 포함합니다:

타입: string

추가된 버전: astro@6.0.0 새로운 기능

컬렉션 내에서 고유해야 하는 엔트리 식별자입니다. 이는 해당 컬렉션에 대해 getLiveEntry()와 함께 사용되는 키입니다.

타입: Record<string, unknown>

추가된 버전: astro@6.0.0 새로운 기능

엔트리의 실제 데이터입니다. 사용자가 컬렉션에 액세스할 때, 이는 컬렉션 스키마에 따라 생성된 TypeScript 타입을 갖게 됩니다.

데이터를 반환하기 전에 검증하고 파싱하는 것은 로더의 책임입니다.

타입: { html: string }

추가된 버전: astro@6.0.0 새로운 기능

엔트리가 HTML로 렌더링된 경우 엔트리의 렌더링된 콘텐츠를 포함하는 객체입니다. 예를 들어 Markdown 엔트리의 렌더링된 콘텐츠나 CMS의 HTML일 수 있습니다.

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

로더가 엔트리에 대해 rendered 속성을 반환하지 않으면 <Content /> 컴포넌트는 아무것도 렌더링하지 않습니다.

타입: CacheHint

추가된 버전: astro@6.0.0 새로운 기능

이 특정 엔트리를 캐싱하는 방법에 대한 힌트를 제공하기 위한 선택적 객체입니다.

타입: { entries: Array<LiveDataEntry<TData>>; cacheHint?: CacheHint; }

추가된 버전: astro@6.0.0 새로운 기능

loadCollection() 메서드에 의해 반환되는 객체 타입입니다. 다음 속성을 포함합니다:

타입: Array<LiveDataEntry<TData>>

추가된 버전: astro@6.0.0 새로운 기능

LiveDataEntry 객체들의 배열입니다.

타입: CacheHint

추가된 버전: astro@6.0.0 새로운 기능

이 컬렉션을 캐싱하는 방법에 대한 지침을 제공하는 선택적 객체입니다. 이 객체는 제공된 경우 각 개별 엔트리에 정의된 캐시 힌트와 병합됩니다.

로더가 LiveDataCollection 또는 LiveDataEntrycacheHint 속성을 통해 반환할 수 있는 객체로, 응답 캐싱을 돕기 위한 힌트를 제공합니다. 다음 속성을 포함합니다:

타입: Array<string>

추가된 버전: astro@6.0.0 새로운 기능

세밀한 캐시 제어를 가능하게 하는 문자열 식별자 배열입니다. 이를 통해 관련 콘텐츠를 그룹화하고 특정 콘텐츠가 변경될 때 캐시된 응답을 선택적으로 무효화할 수 있습니다.

다음 예시는 작성자별로 필터링된 포스트 컬렉션에 대해 캐시 힌트 태그를 정의합니다:

return {
/* ... */
cacheHint: {
tags: ["posts", `posts-${filter.author}`],
},
};

타입: Date

추가된 버전: astro@6.0.0 새로운 기능

콘텐츠의 최종 수정 날짜(예: 컬렉션 내 엔트리의 최근 업데이트 날짜)입니다. 이는 Last-ModifiedIf-Modified-Since와 같은 HTTP 캐시 헤더를 설정하는 데 사용할 수 있습니다.

다음 예시는 제품의 최근 업데이트 날짜를 사용하여 단일 제품에 대한 캐시 힌트를 정의합니다:

return {
/* ... */
cacheHint: {
lastModified: new Date(product.updatedAt)
},
};
기여하기 커뮤니티 후원하기