컨텐츠로 건너뛰기

콘텐츠 컬렉션

Added in: astro@2.0.0

콘텐츠 컬렉션은 모든 Astro 프로젝트에서 콘텐츠 세트를 관리하는 가장 좋은 방법입니다. 컬렉션은 문서를 구성 및 쿼리하고, 편집기에서 자동 완성 및 타입 검사를 활성화하고, 모든 콘텐츠에 대해 TypeScript 타입 안전성을 제공하는 데 도움이 됩니다. Astro v5.0에서는 콘텐츠 컬렉션을 정의하고 쿼리하기 위한 Content Layer API가 도입되었습니다. 이 확장 가능한 고성능 API는 로컬 컬렉션을 위한 내장 콘텐츠 로더를 제공합니다. 원격 콘텐츠의 경우 타사 및 커뮤니티에서 구축한 로더를 사용하거나 자체 사용자 지정 로더를 만들어 모든 소스에서 데이터를 가져올 수 있습니다.

콘텐츠 컬렉션이란 무엇입니까?

섹션 제목: 콘텐츠 컬렉션이란 무엇입니까?

구조적으로 유사한 데이터 집합에서 컬렉션을 정의할 수 있습니다. 블로그 게시물의 디렉터리, 제품 항목의 JSON 파일 또는 동일한 모양의 여러 항목을 나타내는 모든 데이터가 여기에 해당할 수 있습니다.

프로젝트 또는 파일 시스템에 로컬로 저장된 컬렉션에는 Markdown, MDX, Markdoc 또는 JSON 파일 항목이 있을 수 있습니다:

  • 디렉터리src/
  • 디렉터리newsletter/ “newsletter” 컬렉션
    • week-1.md 컬렉션 항목
    • week-2.md 컬렉션 항목
    • week-3.md 컬렉션 항목
  • 디렉터리authors/ “author” 컬렉션
    • authors.json 모든 컬렉션 항목이 포함된 단일 파일

적절한 컬렉션 로더를 사용하면 CMS, 데이터베이스, 헤드리스 결제 시스템 등 모든 외부 소스에서 원격 데이터를 가져올 수 있습니다.

컬렉션을 위한 TypeScript 구성

섹션 제목: 컬렉션을 위한 TypeScript 구성

콘텐츠 컬렉션은 편집기에서 Zod 유효성 검사, 자동 완성 및 타입 검사를 제공하기 위해 TypeScript에 의존합니다. Astro의 TypeScript 설정을 strict 또는 strictest 중 하나로 확장하지 않는 경우 tsconfig.json에 다음 compilerOptions이 설정되어 있는지 확인해야 합니다:

tsconfig.json
{
// "astro/tsconfigs/strict" 또는 "astro/tsconfigs/strictest"에 포함
"extends": "astro/tsconfigs/base",
"compilerOptions": {
"strictNullChecks": true, // `base` 템플릿을 사용하는 경우 추가
"allowJs": true // 필수, 모든 Astro 템플릿에 포함
}
}

개별 컬렉션은 defineCollection()을 사용하여 구성합니다:

  • 데이터 소스를 위한 loader(필수)
  • 타입 안전을 위한 schema(선택 사항이지만 적극 권장!)

컬렉션을 정의하려면 프로젝트에 src/content.config.ts 파일을 만들어야 합니다(.js.mjs 확장자도 지원됨). 이 파일은 Astro가 다음 구조에 따라 콘텐츠 컬렉션을 구성하는 데 사용하는 특수 파일입니다:

src/content.config.ts
// 1. `astro:content`에서 유틸리티 가져오기
import { defineCollection, z } from 'astro:content';
// 2. 로더 가져오기
import { glob, file } from 'astro/loaders';
// 3. 컬렉션 정의
const blog = defineCollection({ /* ... */ });
const dogs = defineCollection({ /* ... */ });
// 4. 컬렉션을 등록하기 위해 단일 `collections` 객체 내보내기
export const collections = { blog, dogs };

Content Layer API를 사용하면 프로젝트에 로컬로 저장하든 원격으로 저장하든 콘텐츠를 가져올 수 있으며, loader 속성을 사용하여 데이터를 검색할 수 있습니다.

Astro는 로컬 콘텐츠를 가져오기 위한 두 가지 내장 로더 함수(glob()file())와 자체 로더를 구성하고 원격 데이터를 가져오기 위한 API에 대한 액세스를 제공합니다.

glob() 로더는 파일 시스템 어디에서나 Markdown, MDX, Markdoc 또는 JSON 파일 디렉터리에서 항목을 만듭니다. 일치시킬 항목 파일의 pattern과 파일이 있는 위치의 base 파일 경로를 인자로 받습니다. 각 항목의 id는 파일 이름으로부터 자동으로 생성됩니다. 항목당 파일이 하나씩 있을 때 이 로더를 사용합니다.

file() 로더는 단일 로컬 파일에서 여러 항목을 생성합니다. 파일의 각 항목에는 고유한 id 키 속성이 있어야 합니다. 이 로더는 파일의 base 파일 경로를 인자로 받고 자동으로 분석할 수 없는 파일을 위해 선택적으로 parser 함수를 인자로 받습니다. 데이터 파일을 객체 배열로 구문 분석할 수 있는 경우 이 로더를 사용합니다.

src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob, file } from 'astro/loaders'; // 레거시 API에서는 사용 불가능
const blog = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),
schema: /* ... */
});
const dogs = defineCollection({
loader: file("src/data/dogs.json"),
schema: /* ... */
}),
});
const probes = defineCollection({
// `loader`는 문자열 패턴뿐만 아니라 여러 패턴의 배열도 허용합니다.
// space-probes 디렉터리에서 "voyager-"로 시작하는 파일을 제외한 모든 Markdown 파일을 로드합니다.
loader: glob({ pattern: ['*.md', '!voyager-*'], base: 'src/data/space-probes' }),
schema: z.object({
name: z.string(),
type: z.enum(['Space Probe', 'Mars Rover', 'Comet Lander']),
launch_date: z.date(),
status: z.enum(['Active', 'Inactive', 'Decommissioned']),
destination: z.string(),
operator: z.string(),
notable_discoveries: z.array(z.string()),
}),
});
export const collections = { blog, dogs, probes };

file() 로더는 parser 함수를 정의하는 두 번째 인수를 받습니다. 이를 통해 사용자 정의 구문 분석기(예: toml.parse 또는 csv-parse)를 지정하여 파일 콘텐츠에서 컬렉션을 생성할 수 있습니다.

file() 로더는 중첩된 JSON 문서가 없는 한 parser가 필요 없이 JSON 및 YAML 파일에서(파일 확장자에 따라) 단일 객체 배열을 자동으로 감지하고 구문 분석합니다. .toml.csv와 같은 다른 파일을 사용하려면 파서 함수를 만들어야 합니다.

다음 예시에서는 .toml 파일을 사용하여 콘텐츠 컬렉션 dogs를 정의합니다:

src/data/dogs.toml
[[dogs]]
id = "..."
age = "..."
[[dogs]]
id = "..."
age = "..."

TOML의 파서를 가져온 후 파일 경로와 parser 함수를 모두 file() 로더에 전달하여 dogs 컬렉션을 프로젝트에 로드할 수 있습니다. 비슷한 과정을 통해 .csv 파일에서 cats 컬렉션을 정의할 수 있습니다:

src/content.config.ts
import { defineCollection } from "astro:content";
import { file } from "astro/loaders";
import { parse as parseToml } from "toml";
import { parse as parseCsv } from "csv-parse/sync";
const dogs = defineCollection({
loader: file("src/data/dogs.toml", { parser: (text) => parseToml(text).dogs }),
schema: /* ... */
})
const cats = defineCollection({
loader: file("src/data/cats.csv", { parser: (text) => parseCsv(text, { columns: true, skipEmptyLines: true })})
});

parser 인수를 사용하면 중첩된 JSON 문서에서 단일 컬렉션을 로드할 수도 있습니다. 예를 들어 이 JSON 파일에는 여러 컬렉션이 포함되어 있습니다:

src/data/pets.json
{"dogs": [{}], "cats": [{}]}

각 컬렉션에 대해 사용자 정의 parserfile() 로더에 전달하여 이러한 컬렉션을 분리할 수 있습니다:

src/content.config.ts
const dogs = defineCollection({
loader: file("src/data/pets.json", { parser: (text) => JSON.parse(text).dogs })
});
const cats = defineCollection({
loader: file("src/data/pets.json", { parser: (text) => JSON.parse(text).cats })
});

사용자 지정 로더 빌드

섹션 제목: 사용자 지정 로더 빌드

사용자 지정 로더를 빌드하여 CMS, 데이터베이스, API 엔드포인트 등 모든 데이터 소스에서 원격 콘텐츠를 가져올 수 있습니다.

로더를 사용해 데이터를 가져오면 원격 데이터에서 컬렉션이 자동으로 만들어집니다. 이렇게 하면 getCollection()render()와 같이 데이터를 쿼리하고 표시하는 컬렉션 전용 API 헬퍼와 스키마 유효성 검사 등 로컬 컬렉션의 모든 이점을 누릴 수 있습니다.

컬렉션 내부에서 로더를 인라인으로 정의하여 항목 배열을 반환하는 비동기 함수로 정의할 수 있습니다.

이는 데이터를 불러와 저장하는 방식을 수동으로 제어할 필요가 없는 로더에 유용합니다. 로더가 호출될 때마다 스토어를 비우고 모든 항목을 다시 불러옵니다.

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: /* ... */
});

반환된 항목들은 컬렉션에 저장되며 getCollection()getEntry() 함수를 사용하여 조회할 수 있습니다.

로딩 프로세스를 더 세밀하게 제어하려면 Content Loader API를 사용하여 로더 객체를 생성할 수 있습니다. 예를 들어, load 메서드에 직접 접근할 수 있어 항목을 점진적으로 업데이트하거나 필요할 때만 스토어를 비우는 로더를 만들 수 있습니다.

Astro 통합이나 Vite 플러그인을 만드는 것처럼, 로더를 NPM 패키지로 배포하여 다른 사람들이 자신의 프로젝트에서 사용할 수 있게 할 수 있습니다.

전체 Content Loader API와 자체 로더를 구축하는 방법에 대한 예시를 참조하세요.

스키마는 Zod 유효성 검사를 통해 컬렉션의 프런트매터나 항목 데이터의 일관성을 강제합니다. 스키마는 데이터를 참조하거나 쿼리할 때 데이터가 예측 가능한 형태로 존재함을 보장합니다. 만약 어떤 파일이 컬렉션 스키마를 위반하면, Astro는 도움이 되는 오류 메시지를 표시합니다.

스키마는 또한 Astro의 자동 TypeScript 타입 생성 기능을 제공합니다. 컬렉션에 스키마를 정의하면 Astro는 자동으로 TypeScript 인터페이스를 생성하고 적용합니다. 그 결과 컬렉션을 쿼리할 때 속성 자동 완성과 타입 검사를 포함한 완전한 TypeScript 지원을 받을 수 있습니다.

컬렉션 항목의 모든 프런트매터나 데이터 속성은 Zod 데이터 타입을 사용하여 정의되어야 합니다:

src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob, file } from 'astro/loaders'; // 레거시 API에서는 사용 불가능
const blog = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
})
});
const dogs = defineCollection({
loader: file("src/data/dogs.json"),
schema: z.object({
id: z.string(),
breed: z.string(),
temperament: z.array(z.string()),
}),
});
export const collections = { blog, dogs };

Zod를 사용한 데이터 타입 정의

섹션 제목: Zod를 사용한 데이터 타입 정의

Astro는 콘텐츠 스키마를 위해 Zod를 사용합니다. Astro는 Zod를 통해 컬렉션의 모든 파일의 데이터를 검증하고, 프로젝트에서 콘텐츠를 쿼리할 때 자동으로 TypeScript 타입을 제공할 수 있습니다.

Astro에서 Zod를 사용하려면 "astro:content"에서 z 유틸리티를 가져옵니다. 이는 Zod 라이브러리를 다시 내보낸 것으로, Zod의 모든 기능을 지원합니다.

// 예시: 자주 사용되는 Zod 데이터 타입 치트 시트
import { z, defineCollection } from 'astro:content';
defineCollection({
schema: z.object({
isDraft: z.boolean(),
title: z.string(),
sortOrder: z.number(),
image: z.object({
src: z.string(),
alt: z.string(),
}),
author: z.string().default('Anonymous'),
language: z.enum(['en', 'es']),
tags: z.array(z.string()),
footnote: z.string().optional(),
// YAML에서 따옴표로 감싸지 않은 날짜는 Date 객체로 해석됩니다
publishDate: z.date(), // e.g. 2024-09-17
// 날짜 문자열(예: "2022-07-08")을 Date 객체로 변환
updatedDate: z.string().transform((str) => new Date(str)),
authorContact: z.string().email(),
canonicalURL: z.string().url(),
})
})
Zod의 README에서 Zod의 작동 방식과 사용 가능한 기능에 대한 전체 문서를 확인하세요.

모든 Zod 스키마 메서드(예: .parse(), .transform())는 일부 제한사항과 함께 사용할 수 있습니다. 특히 image().refine()을 사용한 이미지의 사용자 정의 유효성 검사는 지원되지 않습니다.

컬렉션 항목은 다른 관련 항목을 “참조”할 수도 있습니다.

Collections API의 reference() 함수를 사용하면 컬렉션 스키마의 속성을 다른 컬렉션의 항목으로 정의할 수 있습니다. 예를 들어, 모든 space-shuttle 항목에 pilot 컬렉션의 스키마를 사용하여 타입 검사, 자동 완성, 유효성 검증을 수행하는 pilot 속성을 포함하도록 요구할 수 있습니다.

일반적인 예시로는 JSON으로 저장된 재사용 가능한 작성자 프로필을 참조하거나, 같은 컬렉션에 저장된 관련 게시물 URL을 참조하는 블로그 게시물이 있습니다:

src/content.config.ts
import { defineCollection, reference, z } from 'astro:content';
const blog = defineCollection({
loader: glob({ pattern: '**/[^_]*.md', base: "./src/data/blog" }),
schema: z.object({
title: z.string(),
// `authors` 컬렉션에서 `id`로 단일 작성자 참조
author: reference('authors'),
// `blog` 컬렉션에서 `slug`로 관련 게시물 배열 참조
relatedPosts: z.array(reference('blog')),
})
});
const authors = defineCollection({
loader: glob({ pattern: '**/[^_]*.json', base: "./src/data/authors" }),
schema: z.object({
name: z.string(),
portfolio: z.string().url(),
})
});
export const collections = { blog, authors };

이 예시 블로그 게시물은 관련 게시물들의 id와 게시물 작성자의 id를 지정합니다:

src/data/blog/welcome.md
---
title: "Welcome to my blog"
author: ben-holmes # `src/data/authors/ben-holmes.json` 참조
relatedPosts:
- about-me # `src/data/blog/about-me.md` 참조
- my-year-in-review # `src/data/blog/my-year-in-review.md` 참조
---

Markdown, MDX, Markdoc 또는 JSON 파일에 glob() 로더를 사용할 때, 모든 콘텐츠 항목의 id는 콘텐츠 파일 이름을 기반으로 URL 친화적인 형식으로 자동 생성됩니다. 이 id는 컬렉션에서 직접 항목을 쿼리할 때 사용됩니다. 또한 콘텐츠로부터 새로운 페이지와 URL을 만들 때도 유용합니다.

파일의 프런트매터나 JSON 파일의 데이터 객체에 slug 속성을 추가하여 항목의 자동 생성된 id를 재정의할 수 있습니다. 이는 다른 웹 프레임워크의 “permalink” 기능과 유사합니다.

src/blog/1.md
---
title: My Blog Post
slug: my-custom-id/supports/slashes
---
Your blog post content here.
src/categories/1.json
{
"title": "My Category",
"slug": "my-custom-id/supports/slashes",
"description": "Your category description here."
}

Astro는 컬렉션을 쿼리하고 하나 (또는 여러 개)의 콘텐츠 항목을 반환하는 헬퍼 함수를 제공합니다.

  • getCollection()은 전체 컬렉션을 가져와서 항목 배열을 반환합니다.
  • getEntry()는 컬렉션에서 단일 항목을 가져옵니다.

이들은 고유한 id, 정의된 모든 속성을 포함한 data 객체, 그리고 Markdown, MDX 또는 Markdoc 문서의 컴파일되지 않은 원시 본문을 포함하는 body를 가진 항목들을 반환합니다.

import { getCollection, getEntry } from 'astro:content';
// 컬렉션의 모든 항목을 가져옵니다.
// 컬렉션의 이름을 인자로 필요로 합니다.
const allBlogPosts = await getCollection('blog');
// 컬렉션에서 단일 항목을 가져옵니다.
// 컬렉션 이름과 `id`가 필요합니다
const poodleData = await getEntry('dogs', 'poodle');
CollectionEntry 타입이 반환하는 전체 속성 목록을 확인하세요.

Astro 템플릿에서 콘텐츠 사용

섹션 제목: Astro 템플릿에서 콘텐츠 사용

컬렉션을 쿼리한 후에는 Astro 컴포넌트 템플릿에서 각 항목의 콘텐츠에 직접 접근할 수 있습니다. 예를 들어, data 속성을 사용하여 항목의 프런트매터 정보를 표시하는 블로그 게시물 링크 목록을 만들 수 있습니다.

src/pages/index.astro
---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
---
<h1>My posts</h1>
<ul>
{posts.map(post => (
<li><a href={`/blog/${post.id}`}>{post.data.title}</a></li>
))}
</ul>

쿼리가 완료되면 render() 함수 속성을 사용하여 Markdown과 MDX 항목을 HTML로 렌더링할 수 있습니다. 이 함수를 호출하면 <Content /> 컴포넌트와 렌더링된 모든 제목 목록을 포함한 HTML 콘텐츠에 접근할 수 있습니다.

src/pages/blog/post-1.astro
---
import { getEntry, render } from 'astro:content';
const entry = await getEntry('blog', 'post-1');
const { Content, headings } = await render(entry);
---
<p>Published on: {entry.data.published.toDateString()}</p>
<Content />

컴포넌트는 컬렉션 항목 전체를 prop으로 전달할 수도 있습니다.

TypeScript를 사용하여 컴포넌트의 props를 올바르게 타이핑하기 위해 CollectionEntry 유틸리티를 사용할 수 있습니다. 이 유틸리티는 컬렉션 스키마의 이름과 일치하는 문자열 인자를 받아 해당 컬렉션 스키마의 모든 속성을 상속합니다.

src/components/BlogCard.astro
---
import type { CollectionEntry } from 'astro:content';
interface Props {
post: CollectionEntry<'blog'>;
}
// `post`는 'blog' 컬렉션 스키마 타입과 일치합니다
const { post } = Astro.props;
---

getCollection()은 항목의 iddata 속성을 기반으로 쿼리를 필터링할 수 있는 선택적 “filter” 콜백을 받습니다.

이를 통해 원하는 모든 콘텐츠 조건으로 필터링할 수 있습니다. 예를 들어, draft 같은 속성으로 필터링하여 초안 상태인 블로그 게시물이 게시되는 것을 방지할 수 있습니다:

// 예시: `draft: true`인 콘텐츠 항목 필터링
import { getCollection } from 'astro:content';
const publishedBlogEntries = await getCollection('blog', ({ data }) => {
return data.draft !== true;
});

개발 환경에서는 접근 가능하지만 프로덕션 빌드에서는 제외되는 초안 페이지를 만들 수 있습니다:

// 예시: 프로덕션용 빌드 시에만 `draft: true`인 콘텐츠 항목 필터링
import { getCollection } from 'astro:content';
const blogEntries = await getCollection('blog', ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true;
});

필터 인자는 컬렉션 내에서 중첩된 디렉터리로도 필터링을 할 수 있습니다. id가 전체 중첩 경로를 포함하고 있기 때문에, 각 id의 시작 부분으로 필터링하여 특정 중첩 디렉터리의 항목만 반환할 수 있습니다:

// 예시: 컬렉션의 하위 디렉터리로 항목 필터링
import { getCollection } from 'astro:content';
const englishDocsEntries = await getCollection('docs', ({ id }) => {
return id.startsWith('en/');
});

참조된 데이터에 액세스

섹션 제목: 참조된 데이터에 액세스

스키마에 정의된 모든 참조는 컬렉션 항목을 먼저 쿼리한 후 별도로 쿼리해야 합니다. getEntry() 함수를 사용하여 단일 참조 항목을 반환하거나, getEntries()를 사용하여 반환된 data 객체에서 여러 참조 항목을 가져올 수 있습니다.

src/pages/blog/welcome.astro
---
import { getEntry, getEntries } from 'astro:content';
const blogPost = await getEntry('blog', 'welcome');
// 단일 참조 처리
const author = await getEntry(blogPost.data.author);
// 참조 배열 처리
const relatedPosts = await getEntries(blogPost.data.relatedPosts);
---
<h1>{blogPost.data.title}</h1>
<p>Author: {author.data.name}</p>
<!-- ... -->
<h2>You might also like:</h2>
{relatedPosts.map(post => (
<a href={post.id}>{post.data.title}</a>
))}

콘텐츠로부터 라우트 생성

섹션 제목: 콘텐츠로부터 라우트 생성

콘텐츠 컬렉션은 src/pages/ 디렉터리 외부에 저장됩니다. 이는 기본적으로 컬렉션 항목에 대한 페이지나 라우트가 생성되지 않는다는 것을 의미합니다.

개별 블로그 게시물과 같이 각 컬렉션 항목에 대한 HTML 페이지를 생성하려면 새로운 동적 라우트를 수동으로 생성해야 합니다. 동적 라우트는 들어오는 요청 매개변수(예: src/pages/blog/[...slug].astroAstro.params.slug)를 각 페이지에 맞는 올바른 항목을 가져오는 데 사용합니다.

라우트 생성을 위한 정확한 방법은 페이지가 미리 렌더링되는지(기본값) 또는 서버에서 필요할 때 렌더링되는지에 따라 달라집니다.

정적 출력을 위한 빌드(기본값)

섹션 제목: 정적 출력을 위한 빌드(기본값)

정적 웹사이트를 빌드하는 경우(Astro의 기본 동작), 빌드 시 단일 페이지 컴포넌트(예: src/pages/[slug])에서 여러 페이지를 생성하기 위해 getStaticPaths() 함수를 사용하세요.

getStaticPaths()에서 getCollection()을 호출하여 정적 라우트 빌드에 필요한 컬렉션 데이터를 사용할 수 있습니다. 그런 다음 각 콘텐츠 항목의 id 속성을 사용하여 개별 URL 경로를 생성합니다. 각 페이지는 전체 컬렉션 항목을 prop으로 전달받아 페이지 템플릿에서 사용할 수 있습니다.

src/pages/posts/[id].astro
---
import { getCollection, render } from 'astro:content';
// 1. 모든 컬렉션 항목에 대한 새로운 경로 생성
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map(post => ({
params: { id: post.id },
props: { post },
}));
}
// 2. 템플릿에서는 prop으로부터 항목을 직접 가져올 수 있음
const { post } = Astro.props;
const { Content } = await render(post);
---
<h1>{post.data.title}</h1>
<Content />

blog 컬렉션의 모든 항목에 대해 페이지 라우트가 생성됩니다. 예를 들어, src/blog/hello-world.md에 있는 항목의 idhello-world가 되며, 따라서 최종 URL은 /posts/hello-world/가 됩니다.

동적 웹사이트를 만드는 경우(Astro의 SSR 지원 사용), 빌드 과정에서 경로를 미리 생성할 필요가 없습니다. 대신, 페이지에서 요청을 검사하여(Astro.request 또는 Astro.params 사용) slug를 찾은 다음 getEntry()를 사용하여 가져오면 됩니다.

src/pages/posts/[id].astro
---
import { getEntry, render } from "astro:content";
// 1. 들어오는 서버 요청에서 slug 가져오기
const { id } = Astro.params;
if (id === undefined) {
return Astro.redirect("/404");
}
// 2. 요청의 slug를 사용하여 항목 직접 조회
const post = await getEntry("blog", id);
// 3. 항목이 존재하지 않으면 리디렉션
if (post === undefined) {
return Astro.redirect("/404");
}
// 4. 템플릿에서 항목을 HTML로 렌더링
const { Content } = await render(post);
---
<h1>{post.data.title}</h1>
<Content />

컬렉션 생성이 필요한 경우

섹션 제목: 컬렉션 생성이 필요한 경우

관련된 데이터나 콘텐츠가 공통 구조를 공유하는 그룹이 있을 때마다 컬렉션을 생성할 수 있습니다.

컬렉션 사용의 주요 이점은 다음과 같습니다:

  • 개별 항목이 “올바른지” 또는 “완전한지” 검증하여 프로덕션에서의 오류를 방지할 수 있는 공통 데이터 형태를 정의할 수 있습니다.
  • 페이지에서 콘텐츠를 가져와 렌더링할 때 직관적인 쿼리가 가능하도록 설계된 콘텐츠 중심의 API를 제공합니다(예: import.meta.glob() 대신 getCollection() 사용).
  • 콘텐츠를 가져오기 위한 Content Loader API는 내장 로더와 저수준 API 접근을 모두 제공합니다. 여러 서드파티 및 커뮤니티에서 제작한 로더를 사용할 수 있으며, 원하는 곳에서 데이터를 가져올 수 있는 자체 커스텀 로더를 만들 수도 있습니다.
  • 성능과 확장성이 뛰어납니다. Content Layer API를 통해 빌드 간에 데이터를 캐시할 수 있으며, 수만 개의 콘텐츠 항목도 처리할 수 있습니다.

다음과 같은 경우에 데이터를 컬렉션으로 정의하세요:

  • 동일한 구조(예: 같은 프런트매터 속성을 가진 Markdown 블로그 게시물들)를 공유하는 여러 파일이나 데이터를 정리해야 하는 경우
  • CMS와 같이 원격에 저장된 기존 콘텐츠가 있고, fetch()나 SDK 대신 컬렉션 헬퍼 함수와 Content Layer API를 활용하고 싶은 경우
  • 수만 개의 연관된 데이터를 가져와야 하고, 대규모 처리가 가능한 쿼리와 캐싱 방법이 필요한 경우

컬렉션 생성이 불필요한 경우

섹션 제목: 컬렉션 생성이 불필요한 경우

컬렉션은 동일한 속성을 공유해야 하는 여러 콘텐츠가 있을 때 우수한 구조와 안정성, 그리고 체계를 제공합니다.

다음과 같은 경우에는 컬렉션이 적절한 해결책이 아닐 수 있습니다:

  • 하나 또는 소수의 서로 다른 페이지만 있는 경우. 대신 src/pages/about.astro와 같이 콘텐츠를 직접 포함하는 개별 페이지 컴포넌트를 만드는 것을 고려하세요.
  • PDF와 같이 Astro가 처리하지 않는 파일을 표시하는 경우. 대신 이러한 정적 자산을 프로젝트의 public/ 디렉터리에 두세요.
  • 데이터 소스가 가져오기를 위한 자체 SDK/클라이언트 라이브러리를 보유하고 있으며, 이 라이브러리가 콘텐츠 로더와 호환되지 않거나 콘텐츠 로더를 제공하지 않아 해당 라이브러리를 직접 사용하는 것을 선호하는 경우
  • 실시간으로 업데이트가 필요한 API를 사용하고 있는 경우. 콘텐츠 컬렉션은 빌드 시에만 업데이트되므로, 실시간 데이터가 필요한 경우에는 요청 시 렌더링을 통해 파일 가져오기 또는 데이터 가져오기와 같은 다른 방법을 사용하세요.
기여하기

여러분의 생각을 들려주세요!

GitHub Issue 생성

우리에게 가장 빨리 문제를 알려줄 수 있어요.

커뮤니티