튜토리얼 - 콘텐츠 컬렉션으로 확장
콘텐츠 컬렉션은 블로그 게시물과 같은 유사한 콘텐츠 그룹을 관리하는 강력한 방법입니다. 컬렉션은 문서를 구성하고, YAML 프런트매터의 유효성을 검사하고, 모든 콘텐츠에 대해 TypeScript 타입 안전성을 제공하는 데 도움이 됩니다(직접 TypeScript를 작성하지 않은 경우에도 마찬가지).
요구 사항
- 블로그 게시물 폴더를
src/content/
로 이동하세요. - 블로그 게시물의 프런트매터를 정의하는 스키마 만드세요.
getCollection()
함수를 사용하여 블로그 게시물 콘텐츠 및 메타데이터를 가져오세요.
필요 조건
섹션 제목: 필요 조건src/pages/
폴더에 Markdown 또는 MDX 파일이 있는 기존 Astro 프로젝트가 필요합니다.
이 튜토리얼에서는 블로그 구축 튜토리얼의 완성된 프로젝트를 사용하여 블로그를 콘텐츠 컬렉션으로 변환하는 방법을 보여줍니다. 해당 코드베이스를 로컬에서 포크하여 사용하거나 StackBlitz에서 블로그 튜토리얼의 코드를 편집하여 브라우저에서 튜토리얼을 완료할 수 있습니다.
대신 여러분의 Astro 프로젝트에서 이 단계를 수행할 수 있지만, 코드베이스에 대한 지침을 조정해야 합니다.
먼저 이 짧은 튜토리얼을 완료하려면 샘플 프로젝트를 사용하는 것이 좋습니다. 그런 다음 배운 내용을 사용하여 자신의 프로젝트에서 콘텐츠 컬렉션을 만들 수 있습니다.
블로그 튜토리얼 코드 구축
섹션 제목: 블로그 튜토리얼 코드 구축블로그 구축 튜토리얼 개요에서 Astro의 내장 파일 기반 라우팅에 대해 배웠습니다. src/pages/
폴더의 모든 .astro
, .md
, .mdx
파일은 자동으로 사이트의 페이지가 됩니다.
https://example.com/posts/post-1/
에 첫 번째 블로그 게시물을 추가하기 위해 /posts/
폴더를 만들고 post-1.md
파일을 추가했습니다. 그런 다음, 사이트에 새 블로그 게시물을 추가 할 때마다 이 폴더에 새 Markdown 파일을 추가했습니다.
페이지 vs 컬렉션
섹션 제목: 페이지 vs 컬렉션콘텐츠 컬렉션을 사용하는 경우에도 소개 페이지와 같은 개별 페이지에 대해서는 src/pages/
폴더를 계속 사용하게 됩니다. 그러나 블로그 게시물을 특별한 src/content/
폴더로 이동하면 보다 강력하고 성능이 뛰어난 API를 사용하여 블로그 게시물 색인을 생성하고 개별 블로그 게시물을 표시할 수 있습니다.
동시에 Astro의 작업을 도와주는 각 게시물에 대한 공통 구조를 정의하는 **스키마**를 갖게 되므로 코드 편집기에서 더 나은 지침과 자동 완성 기능을 얻을 수 있습니다. 스키마에서는 description이나 author와 같은 프런트매터 속성이 필요한 시기와 각 속성이 어떤 데이터 타입이어야 하는지 (문자열이나 배열 등) 지정할 수 있습니다. 이로 인해, 문제가 무엇인지 정확하게 알려주는 설명 오류 메시지를 통해 많은 실수를 더 빨리 발견할 수 있습니다.
안내서에서 Astro의 콘텐츠 컬렉션에 대해 자세히 읽어보거나 아래 지침에 따라 기본 블로그를 src/pages/posts/
에서 src/content/posts/
로 변환해 보세요.
지식을 테스트해보세요
섹션 제목: 지식을 테스트해보세요-
어떤 유형의 페이지를
src/pages/
에 보관하시겠습니까? -
블로그 게시물을 콘텐츠 컬렉션으로 이동할 때의 이점이 아닌 것은 무엇입니까?
-
콘텐츠 컬렉션은 TypeScript를 사용합니다…
콘텐츠 컬렉션으로 블로그 튜토리얼 확장
섹션 제목: 콘텐츠 컬렉션으로 블로그 튜토리얼 확장아래 단계에서는 블로그 게시물에 대한 콘텐츠 컬렉션을 생성하여 블로그 구축 튜토리얼의 최종 제품을 확장하는 방법을 보여줍니다.
종속성 업그레이드
섹션 제목: 종속성 업그레이드-
Astro의 최신 버전으로 업그레이드하고 터미널에서 다음 명령을 실행하여 모든 통합을 최신 버전으로 업그레이드하세요.
Terminal window # Astro v3.x로 업그레이드npm install astro@latest# 예: 블로그 튜토리얼의 Preact 통합 업그레이드npm install @astrojs/preact@latestTerminal window # Astro v3.x로 업그레이드pnpm add astro@latest# 예: 블로그 튜토리얼의 Preact 통합 업그레이드pnpm add @astrojs/preact@latestTerminal window # Astro v3.x로 업그레이드yarn add astro@latest# 예: 블로그 튜토리얼의 Preact 통합 업그레이드yarn add @astrojs/preact@latest자신의 프로젝트를 사용하는 경우 설치한 모든 종속성을 업데이트해야 합니다. 예시의 블로그 튜토리얼 코드베이스는 Preact 통합만 사용합니다.
-
블로그 튜토리얼에서는
base
(가장 덜 엄격한) TypeScript 설정을 사용합니다. 콘텐츠 컬렉션을 사용하려면,strict
또는strictest
설정을 사용하거나tsconfig.json
에 두 가지 옵션을 추가하여 콘텐츠 컬렉션에 대한 TypeScript를 설정해야 합니다.블로그 튜토리얼 예시의 나머지 부분에서 TypeScript를 작성하지 않고 콘텐츠 컬렉션을 사용하려면 다음 두 가지 TypeScript 구성 옵션을 구성 파일에 추가하세요.
tsconfig.json {// 참고: "astro/tsconfigs/strict" 또는 "astro/tsconfigs/strictest"를 사용하는 경우 변경이 필요하지 않습니다."extends": "astro/tsconfigs/base","compilerOptions": {"strictNullChecks": true,"allowJs": true}}
블로그 게시물에 대한 컬렉션 만들기
섹션 제목: 블로그 게시물에 대한 컬렉션 만들기-
src/content/posts/
라는 새 컬렉션 (폴더)을 만듭니다. -
src/pages/posts/
에 있는 모든 기존 블로그 게시물(.md
파일)을 이 새 컬렉션으로 이동합니다. -
postsCollection
의 스키마 정의를 위한src/content/config.ts
파일을 생성합니다. 기존 블로그 튜토리얼 코드의 경우, 블로그 게시물에 사용되는 모든 프런트매터 속성을 정의하려면 다음 내용을 파일에 추가하세요.src/content/config.ts // `astro:content`에서 유틸리티 가져오기import { z, defineCollection } from "astro:content";// 각 컬렉션에 대한 `type` 및 `schema` 정의const postsCollection = defineCollection({type: 'content',schema: z.object({title: z.string(),pubDate: z.date(),description: z.string(),author: z.string(),image: z.object({url: z.string(),alt: z.string()}),tags: z.array(z.string())})});// 컬렉션을 등록하려면 단일 'collections' 객체를 내보내세요.export const collections = {posts: postsCollection,};
컬렉션에서 페이지 생성
섹션 제목: 컬렉션에서 페이지 생성-
src/pages/posts/[...slug].astro
라는 페이지 파일을 만듭니다. Markdown 및 MDX 파일은 컬렉션 내에 있을 때 더 이상 자동으로 Astro의 파일 기반 라우팅을 사용하는 페이지가 되지 않으므로, 각 개별 블로그 게시물 생성을 담당하는 페이지를 만들어야 합니다. -
각 블로그 게시물의 슬러그와 페이지 콘텐츠를 생성하기 위해 컬렉션을 쿼리해야 합니다. 이를 위해서 다음 코드를 추가합니다.
src/pages/posts/[...slug].astro ---import { getCollection } from 'astro:content';import MarkdownPostLayout from '../../layouts/MarkdownPostLayout.astro';export async function getStaticPaths() {const blogEntries = await getCollection('posts');return blogEntries.map(entry => ({params: { slug: entry.slug }, props: { entry },}));}const { entry } = Astro.props;const { Content } = await entry.render();--- -
Markdown 페이지 레이아웃에서 게시물
<Content />
를 렌더링합니다. 이를 통해 모든 게시물에 대한 공통 레이아웃을 지정할 수 있습니다.src/pages/posts/[...slug].astro ---import { getCollection } from 'astro:content';import MarkdownPostLayout from '../../layouts/MarkdownPostLayout.astro';export async function getStaticPaths() {const blogEntries = await getCollection('posts');return blogEntries.map(entry => ({params: { slug: entry.slug }, props: { entry },}));}const { entry } = Astro.props;const { Content } = await entry.render();---<MarkdownPostLayout frontmatter={entry.data}><Content /></MarkdownPostLayout> -
각 개별 게시물의 프런트매터에서
layout
정의를 제거하세요. 이제 렌더링 시 콘텐츠가 레이아웃으로 래핑되므로 이 속성은 더 이상 필요하지 않습니다.src/content/posts/post-1.md ---layout: ../../layouts/MarkdownPostLayout.astrotitle: '나의 첫 블로그 게시물'pubDate: 2022-07-01...---
Astro.glob()
을 getCollection()
으로 대체
섹션 제목: Astro.glob()을 getCollection()으로 대체-
튜토리얼의 블로그 페이지(
src/pages/blog.astro/
)처럼, 블로그 게시물 목록이 있는 곳이라면 어디서든Astro.glob()
을getCollection()
로 대체하여 Markdown 파일에서 콘텐츠 및 메타데이터를 가져올 수 있습니다.src/pages/blog.astro ---import { getCollection } from "astro:content";import BaseLayout from "../layouts/BaseLayout.astro";import BlogPost from "../components/BlogPost.astro";const pageTitle = "My Astro Learning Blog";const allPosts = await Astro.glob("../pages/posts/*.md");const allPosts = await getCollection("posts");--- -
각
post
마다 반환되는 데이터에 대한 참조도 업데이트해야 합니다. 이제 각 객체의data
속성에서 자신의 프런트매터 값을 찾을 수 있습니다. 또한, 컬렉션을 사용할 때 각post
객체에는 전체 URL이 아닌 페이지의slug
가 포함되어 있습니다.src/pages/blog.astro ---import { getCollection } from "astro:content";import BaseLayout from "../layouts/BaseLayout.astro";import BlogPost from "../components/BlogPost.astro";const pageTitle = "내 Astro 학습 블로그";const allPosts = await getCollection("posts");---<BaseLayout pageTitle={pageTitle}><p>제가 Astro를 배우게 된 과정을 게시하는 곳입니다.</p><ul>{allPosts.map((post) => (<BlogPost url={post.url} title={post.frontmatter.title} />)}<BlogPost url={`/posts/${post.slug}/`} title={post.data.title} />))}</ul></BaseLayout> -
또한 튜토리얼 블로그 프로젝트는
src/pages/tags/[tag].astro
를 사용하여 태그별 페이지를 동적으로 생성하고,src/pages/tags/index.astro
에 태그 목록을 표시합니다.위와 동일한 변경 사항을 다음 두 파일에 적용합니다.
Astro.glob()
을 사용하는 대신getCollection("posts")
을 사용하여 모든 블로그 게시물에 대한 데이터를 가져옵니다.frontmatter
대신data
를 사용하여 모든 프런트매터 값에 접근합니다./posts/
경로에 게시물의slug
를 추가하여 페이지 URL을 만듭니다.
개별 태그 페이지를 생성하는 페이지는 이제 다음과 같습니다.
src/pages/tags/[tag].astro ---import { getCollection } from "astro:content";import BaseLayout from "../../layouts/BaseLayout.astro";import BlogPost from "../../components/BlogPost.astro";export async function getStaticPaths() {const allPosts = await getCollection("posts");const uniqueTags = [...new Set(allPosts.map((post) => post.data.tags).flat())];return uniqueTags.map((tag) => {const filteredPosts = allPosts.filter((post) =>post.data.tags.includes(tag));return {params: { tag },props: { posts: filteredPosts },};});}const { tag } = Astro.params;const { posts } = Astro.props;---<BaseLayout pageTitle={tag}><p>{tag} 태그가 포함된 게시물</p><ul>{ posts.map((post) => <BlogPost url={`/posts/${post.slug}/`} title={post.data.title} />) }</ul></BaseLayout>직접 시도하기 - 태그 색인 페이지에서 쿼리를 업데이트하세요.
섹션 제목: 직접 시도하기 - 태그 색인 페이지에서 쿼리를 업데이트하세요.위와 동일한 단계에 따라
getCollection
을 가져와 사용하여src/pages/tags/index.astro
에 있는 블로그 게시물에 사용된 태그를 가져옵니다.코드 보기
src/pages/tags/index.astro ---import { getCollection } from "astro:content";import BaseLayout from "../../layouts/BaseLayout.astro";const allPosts = await getCollection("posts");const tags = [...new Set(allPosts.map((post) => post.data.tags).flat())];const pageTitle = "Tag Index";---...
스키마와 일치하도록 프런트매터 값을 업데이트하세요.
섹션 제목: 스키마와 일치하도록 프런트매터 값을 업데이트하세요.-
필요하다면, 프로젝트 전체에서 컬렉션 스키마와 일치하지 않는 레이아웃과 같은 프런트매터 값을 업데이트하세요.
블로그 튜토리얼 예시에서
pubDate
는 문자열이었습니다. 이제 게시물의 프런트매터의 타입을 정의하는 스키마에 따라pubDate
는Date
객체가 됩니다.블로그 게시물 레이아웃에 날짜를 렌더링하려면, 날짜를 문자열로 변환하세요.
src/layouts/MarkdownPostLayout.astro ...<BaseLayout pageTitle={frontmatter.title}><p>{frontmatter.pubDate.toString().slice(0,10)}</p><p><em>{frontmatter.description}</em></p><p>작성자: {frontmatter.author}</p><img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} />...
RSS 함수 업데이트
섹션 제목: RSS 함수 업데이트-
마지막으로, 튜토리얼 블로그 프로젝트에는 RSS 피드가 포함되어 있습니다. 또한 이 함수는
getCollection()
을 사용하여 블로그 게시물의 정보를 반환해야 합니다. 그런 다음 반환된data
객체를 사용하여 RSS 항목을 생성합니다.src/pages/rss.xml.js import rss from '@astrojs/rss';import { pagesGlobToRssItems } from '@astrojs/rss';import { getCollection } from 'astro:content';export async function GET(context) {const posts = await getCollection("posts");return rss({title: 'Astro 학습자 | 블로그',description: 'Astro를 배우는 나의 여정',site: context.site,items: await pagesGlobToRssItems(import.meta.glob('./**/*.md')),items: posts.map((post) => ({title: post.data.title,pubDate: post.data.pubDate,description: post.data.description,link: `/posts/${post.slug}/`,})),customData: `<language>ko-KR</language>`,})}
콘텐츠 컬렉션을 사용하는 블로그 튜토리얼의 전체 예시를 보려면, 튜토리얼 저장소의 Content Collections 브랜치를 참조하세요.
Learn