乐闻世界logo
搜索文章和话题

What are Astro's Content Collections? How do you use them to manage blog posts or documentation?

2月21日 16:14

Astro's Content Collections is a powerful feature for managing structured content like blog posts, documentation, product catalogs, etc. It provides type safety, performance optimization, and improved developer experience.

Core Concepts:

Content Collections allow you to organize content in the src/content directory and access it through a type-safe API.

Setting Up Content Collections:

  1. Create Collection Configuration:

    typescript
    // src/content/config.ts import { defineCollection, z } from 'astro:content'; const blog = defineCollection({ type: 'content', // Use Markdown/MDX schema: z.object({ title: z.string(), description: z.string(), publishDate: z.coerce.date(), tags: z.array(z.string()), image: z.string().optional(), }), }); const products = defineCollection({ type: 'data', // Use JSON/YAML schema: z.object({ name: z.string(), price: z.number(), category: z.string(), }), }); export const collections = { blog, products };
  2. Create Content Files:

    markdown
    <!-- src/content/blog/my-first-post.md --> --- title: "My First Post" description: "This is the post description" publishDate: 2024-01-15 tags: ["astro", "tutorial"] image: "/images/post-1.jpg" --- This is the post content...
    json
    // src/content/products/product-1.json { "name": "Product 1", "price": 99.99, "category": "Electronics" }

Querying Content Collections:

astro
--- import { getCollection } from 'astro:content'; // Get all blog posts const allPosts = await getCollection('blog'); // Sort by date const posts = allPosts .filter(post => post.data.publishDate <= new Date()) .sort((a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf()); // Get posts with specific tags const astroPosts = await getCollection('blog', ({ data }) => { return data.tags.includes('astro'); }); --- <h1>Blog Posts</h1> {posts.map(post => ( <article> <h2>{post.data.title}</h2> <p>{post.data.description}</p> <time>{post.data.publishDate.toLocaleDateString()}</time> <a href={`/blog/${post.slug}`}>Read More</a> </article> ))}

Getting a Single Entry:

astro
--- import { getEntry } from 'astro:content'; import type { CollectionEntry } from 'astro:content'; // Get single entry by slug const post = await getEntry('blog', 'my-first-post'); // Or get from params const { slug } = Astro.params; const post = await getEntry('blog', slug); if (!post) { return Astro.redirect('/404'); } const { Content } = await post.render(); --- <h1>{post.data.title}</h1> <p>{post.data.description}</p> <Content />

Dynamic Routes with Content Collections:

astro
--- // src/pages/blog/[slug].astro import { getCollection } from 'astro:content'; export async function getStaticPaths() { const posts = await getCollection('blog'); return posts.map(post => ({ params: { slug: post.slug }, props: { post }, })); } const { post } = Astro.props; const { Content } = await post.render(); --- <h1>{post.data.title}</h1> <Content />

Using MDX:

markdown
--- title: "Post with MDX" description: "Markdown with JSX support" publishDate: 2024-01-20 tags: ["mdx", "astro"] --- import { Counter } from '../../components/Counter.jsx'; This is regular Markdown content. <Counter /> You can use any component here!

Advantages of Content Collections:

  1. Type Safety:

    • Define content structure using Zod schemas
    • TypeScript automatically infers types
    • Compile-time validation
  2. Performance Optimization:

    • Process content at build time
    • Automatically generate routes
    • Avoid runtime parsing
  3. Developer Experience:

    • IDE autocomplete
    • Type checking
    • Error hints
  4. Flexibility:

    • Supports Markdown, MDX, JSON, YAML
    • Custom schemas
    • Pre-data processing

Advanced Usage:

  1. Nested Directories:

    shell
    src/content/ ├── blog/ │ ├── 2024/ │ │ ├── january/ │ │ │ └── post.md │ │ └── february/ │ │ └── post.md │ └── 2023/ │ └── post.md └── docs/ └── guide.md
  2. Custom Renderers:

    typescript
    // src/content/config.ts import { defineCollection, z } from 'astro:content'; const blog = defineCollection({ type: 'content', schema: z.object({ title: z.string(), }), // Custom renderer render: async ({ entry }) => { // Custom rendering logic return entry.render(); }, });
  3. Content Transformation:

    typescript
    // src/content/config.ts const blog = defineCollection({ type: 'content', schema: z.object({ title: z.string(), date: z.coerce.date(), }), transform: async (data, id) => { // Transform data return { ...data, slug: id.replace('.md', ''), }; }, });

Best Practices:

  1. Use Zod schemas to define clear content structures
  2. Create separate collections for different content types
  3. Leverage TypeScript for type safety
  4. Use getStaticPaths to generate dynamic routes
  5. Process all content at build time to avoid runtime overhead

Content Collections is the best way to handle structured content in Astro, especially suitable for content-driven websites like blogs, documentation, and product catalogs.

标签:Astro