콘텐츠 쿼리
EmDash는 Astro 페이지와 컴포넌트에서 콘텐츠를 검색하기 위한 쿼리 함수를 제공합니다. 이러한 함수는 Astro의 라이브 콘텐츠 컬렉션 패턴을 따르며, 오류 처리가 포함된 구조화된 결과를 반환합니다.
쿼리 함수
섹션 제목: “쿼리 함수”EmDash는 두 가지 주요 쿼리 함수를 내보냅니다:
| 함수 | 목적 | 반환 값 |
|---|---|---|
getEmDashCollection | 특정 콘텐츠 유형의 모든 항목 검색 | { entries, error } |
getEmDashEntry | ID 또는 슬러그로 단일 항목 검색 | { entry, error, isPreview } |
emdash에서 가져옵니다:
import { getEmDashCollection, getEmDashEntry } from "emdash";모든 항목 가져오기
섹션 제목: “모든 항목 가져오기”getEmDashCollection을 사용하여 특정 콘텐츠 유형의 모든 항목을 검색합니다:
astro title="src/pages/posts.astro"---import { getEmDashCollection } from "emdash";
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) { console.error("Failed to load posts:", error);}---
<ul> {posts.map((post) => ( <li>{post.data.title}</li> ))}</ul>로케일로 필터링
섹션 제목: “로케일로 필터링”i18n이 활성화된 경우, 특정 언어의 콘텐츠를 검색하려면 로케일로 필터링합니다:
// French postsconst { entries: frenchPosts } = await getEmDashCollection("posts", { locale: "fr", status: "published",});
// 현재 요청 로케일 사용const { entries: localizedPosts } = await getEmDashCollection("posts", { locale: Astro.currentLocale, status: "published",});단일 항목의 경우, locale을 세 번째 인수로 전달합니다:
const { entry: post } = await getEmDashEntry("posts", "my-post", { locale: Astro.currentLocale,});locale이 생략되면 요청의 현재 로케일로 기본 설정됩니다. 요청된 로케일에 대한 번역이 존재하지 않으면 폴백 체인이 따라집니다.
상태로 필터링
섹션 제목: “상태로 필터링”게시됨 또는 초안 콘텐츠만 검색합니다:
// Only published postsconst { entries: published } = await getEmDashCollection("posts", { status: "published",});
// 초안만const { entries: drafts } = await getEmDashCollection("posts", { status: "draft",});결과 제한
섹션 제목: “결과 제한”반환되는 항목 수를 제한합니다:
// Get the 5 most recent postsconst { entries: recentPosts } = await getEmDashCollection("posts", { status: "published", limit: 5,});분류로 필터링
섹션 제목: “분류로 필터링”카테고리, 태그 또는 사용자 정의 분류 용어로 항목을 필터링합니다:
// Posts in the "news" categoryconst { entries: newsPosts } = await getEmDashCollection("posts", { status: "published", where: { category: "news" },});
// "javascript" 태그가 있는 게시물const { entries: jsPosts } = await getEmDashCollection("posts", { status: "published", where: { tag: "javascript" },});
// 여러 용어 중 하나와 일치하는 게시물const { entries: featuredNews } = await getEmDashCollection("posts", { status: "published", where: { category: ["news", "featured"] },});where 필터는 단일 분류에 대해 여러 값이 제공될 때 OR 논리를 사용합니다.
오류 처리
섹션 제목: “오류 처리”신뢰성이 중요한 경우 항상 오류를 확인하세요:
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) { // 로그 기록 및 우아하게 처리 console.error("게시물 로드 실패:", error); return new Response("서버 오류", { status: 500 });}단일 항목 가져오기
섹션 제목: “단일 항목 가져오기”getEmDashEntry를 사용하여 ID 또는 슬러그로 하나의 항목을 검색합니다:
astro title="src/pages/posts/[slug].astro"---import { getEmDashEntry } from "emdash";import { PortableText } from "emdash/ui";
const { slug } = Astro.params;const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) { return new Response("서버 오류", { status: 500 });}
if (!post) { return Astro.redirect("/404");}---
<article> <h1>{post.data.title}</h1> <PortableText value={post.data.content} /></article>항목 반환 유형
섹션 제목: “항목 반환 유형”getEmDashEntry는 결과 객체를 반환합니다:
interface EntryResult<T> { entry: ContentEntry<T> | null; // null if not found error?: Error; // Only set for actual errors (not "not found") isPreview: boolean; // true if viewing preview/draft content}
interface ContentEntry<T> { id: string; data: T; edit: EditProxy; // Visual editing annotations}entry 내의 data 객체는 콘텐츠 유형에 정의된 모든 필드를 포함합니다. edit 프록시는 시각적 편집 주석을 제공합니다(아래 참조).
미리보기 모드
섹션 제목: “미리보기 모드”EmDash는 미들웨어를 통해 미리보기를 자동으로 처리합니다. URL에 유효한 _preview 토큰이 포함되어 있으면, 미들웨어가 이를 확인하고 요청 컨텍스트를 설정합니다. 그러면 쿼리 함수들이 특별한 매개변수 없이 초안 콘텐츠를 제공합니다:
astro title="src/pages/posts/[...slug].astro"---import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;
// 특별한 미리보기 처리 필요 없음 — 미들웨어가 자동으로 처리합니다const { entry, isPreview, error } = await getEmDashEntry("posts", slug);
if (error) { return new Response("서버 오류", { status: 500 });}
if (!entry) { return Astro.redirect("/404");}---
{isPreview && ( <div class="preview-banner"> Viewing preview. This content is not published. </div>)}
<article> <h1>{entry.data.title}</h1> <PortableText value={entry.data.content} /></article>시각적 편집
섹션 제목: “시각적 편집”쿼리 함수에 의해 반환되는 모든 항목에는 템플릿에 주석을 달기 위한 edit 프록시가 포함됩니다. 인증된 편집자를 위한 인라인 편집을 활성화하려면 이를 요소에 전개하세요:
<article {...entry.edit}> <h1 {...entry.edit.title}>{entry.data.title}</h1> <div {...entry.edit.content}> <PortableText value={entry.data.content} /> </div></article>편집 모드에서 {...entry.edit.title}은 시각적 편집 도구 모음이 인라인 편집을 활성화하는 데 사용하는 data-emdash-ref 속성을 생성합니다. 프로덕션에서는 프록시 전개가 출력을 생성하지 않습니다 — 런타임 비용이 없습니다.
결과 정렬
섹션 제목: “결과 정렬”getEmDashCollection은 정렬 순서를 보장하지 않습니다. 템플릿에서 결과를 정렬하세요:
const { entries: posts } = await getEmDashCollection("posts", { status: "published",});
// 게시 날짜로 정렬, 최신순const sorted = posts.sort( (a, b) => (b.data.publishedAt?.getTime() ?? 0) - (a.data.publishedAt?.getTime() ?? 0),);일반적인 정렬 패턴
섹션 제목: “일반적인 정렬 패턴”// Alphabetical by titleposts.sort((a, b) => a.data.title.localeCompare(b.data.title));
// 사용자 정의 순서 필드로posts.sort((a, b) => (a.data.order ?? 0) - (b.data.order ?? 0));
// 무작위 순서posts.sort(() => Math.random() - 0.5);TypeScript 유형
섹션 제목: “TypeScript 유형”컬렉션에 대한 TypeScript 유형을 생성합니다:
npx emdash types이렇게 하면 각 컬렉션에 대한 인터페이스가 포함된 .emdash/types.ts가 생성됩니다. 타입 안전성을 위해 사용하세요:
import { getEmDashCollection, getEmDashEntry } from "emdash";import type { Post } from "../../.emdash/types";
// 타입 안전한 컬렉션 쿼리const { entries: posts } = await getEmDashCollection<Post>("posts");// posts는 ContentEntry<Post>[]
// 타입 안전한 항목 쿼리const { entry: post } = await getEmDashEntry<Post>("posts", "my-post");// post는 ContentEntry<Post> | null정적 vs 서버 렌더링
섹션 제목: “정적 vs 서버 렌더링”EmDash 콘텐츠는 정적 및 서버 렌더링 페이지 모두에서 작동합니다.
정적 (사전 렌더링)
섹션 제목: “정적 (사전 렌더링)”정적 페이지의 경우, 빌드 시점에 경로를 생성하려면 getStaticPaths를 사용하세요:
astro title="src/pages/posts/[slug].astro"---import { getEmDashCollection, getEmDashEntry } from "emdash";
export async function getStaticPaths() { const { entries: posts } = await getEmDashCollection("posts", { status: "published", });
return posts.map((post) => ({ params: { slug: post.data.slug }, }));}
const { slug } = Astro.params;const { entry: post } = await getEmDashEntry("posts", slug);---서버 렌더링
섹션 제목: “서버 렌더링”서버 렌더링 페이지의 경우, 콘텐츠를 직접 쿼리합니다:
astro title="src/pages/posts/[slug].astro"---export const prerender = false;
import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) { return new Response("서버 오류", { status: 500 });}
if (!post) { return new Response(null, { status: 404 });}---성능 고려사항
섹션 제목: “성능 고려사항”EmDash는 캐싱을 자동으로 처리하는 Astro의 라이브 콘텐츠 컬렉션을 사용합니다. 서버 렌더링 페이지의 경우 HTTP 캐시 헤더를 추가하는 것을 고려하세요:
---const { entries: posts } = await getEmDashCollection("posts", { status: "published",});
// 5분 동안 캐시Astro.response.headers.set("Cache-Control", "public, max-age=300");---중복 쿼리 방지
섹션 제목: “중복 쿼리 방지”한 번 쿼리하여 데이터를 컴포넌트에 전달하세요:
astro title="src/pages/index.astro"---import { getEmDashCollection } from "emdash";import PostList from "../../components/PostList.astro";import Sidebar from "../../components/Sidebar.astro";
// 한 번 쿼리const { entries: posts } = await getEmDashCollection("posts", { status: "published",});
const featured = posts.filter((p) => p.data.featured);const recent = posts.slice(0, 5);---
<PostList posts={featured} /><Sidebar posts={recent} />