Content Collections
ใน Next.js คุณมักใช้ contentlayer หรือ fs + gray-matter เพื่อโหลดไฟล์ MDX พร้อม type safety Astro มี content collections built-in: วางไฟล์ MD/MDX ใน src/content/<collection>/ กำหนด schema ด้วย zod ใน src/content.config.ts แล้วใช้ getCollection('blog') ที่ไหนก็ได้ในโปรเจกต์ — มี type safety เต็มรูปแบบ ไม่ต้องใช้ library ของ third-party
ต้องใช้โปรเจกต์ Astro เต็มรูปแบบ ใช้
npm create astro@latestเพื่อสร้างโปรเจกต์
การกำหนด collection: contentlayer vs Astro
หัวข้อที่มีชื่อว่า “การกำหนด collection: contentlayer vs Astro”// contentlayer.config.ts (Next.js)import { defineDocumentType, makeSource } from 'contentlayer/source-files';
export const Post = defineDocumentType(() => ({ name: 'Post', filePathPattern: 'blog/**/*.mdx', contentType: 'mdx', fields: { title: { type: 'string', required: true }, date: { type: 'date', required: true }, tags: { type: 'list', of: { type: 'string' } }, },}));
export default makeSource({ contentDirPath: 'content', documentTypes: [Post] });
// In a page:// import { allPosts } from 'contentlayer/generated';// src/content.config.ts (Astro)import { defineCollection, z } from 'astro:content';
const blog = defineCollection({ type: 'content', schema: z.object({ title: z.string(), date: z.coerce.date(), tags: z.array(z.string()).optional(), }),});
export const collections = { blog };
// In a page:// import { getCollection } from 'astro:content';// const posts = await getCollection('blog');Schema อยู่ใน src/content.config.ts — Astro ตรวจสอบทุกไฟล์ใน collection ตอน build time และแสดง type errors ใน editor ของคุณ
content.config.ts
หัวข้อที่มีชื่อว่า “content.config.ts”import { defineCollection, z } from 'astro:content';
const blog = defineCollection({ type: 'content', // 'content' for MD/MDX, 'data' for JSON/YAML schema: z.object({ title: z.string(), description: z.string().optional(), date: z.coerce.date(), draft: z.boolean().default(false), tags: z.array(z.string()).default([]), }),});
export const collections = { blog };การแสดงรายการ collection entries
หัวข้อที่มีชื่อว่า “การแสดงรายการ collection entries”---import { getCollection } from 'astro:content';
const posts = await getCollection('blog', ({ data }) => !data.draft);const sorted = posts.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());---<html lang="en"> <head><meta charset="utf-8" /><title>Blog</title></head> <body> <h1>Blog</h1> <ul> {sorted.map((post) => ( <li> <a href={`/blog/${post.slug}/`}>{post.data.title}</a> <time>{post.data.date.toLocaleDateString()}</time> </li> ))} </ul> </body></html>argument ที่สองของ getCollection คือ optional filter function — ที่นี่ใช้กรอง drafts ออก post.data มี type จาก zod schema เต็มรูปแบบ