MCP HubMCP Hub
返回技能列表

content-collections

jezweb
更新于 Today
1559 次查看
33
4
33
在 GitHub 上查看
wordreacttestingautomationdesigndata

关于

This skill provides a production-tested setup for Content Collections, a TypeScript-first tool that transforms Markdown/MDX files into type-safe data collections with Zod validation. Use it when building blogs, documentation sites, or content-heavy Vite + React applications to ensure type safety and automatic content validation. It covers everything from Vite plugin configuration and MDX compilation to deployment optimization and schema validation.

快速安装

Claude Code

推荐
插件命令推荐
/plugin add https://github.com/jezweb/claude-skills
Git 克隆备选方式
git clone https://github.com/jezweb/claude-skills.git ~/.claude/skills/content-collections

在 Claude Code 中复制并粘贴此命令以安装该技能

技能文档

Content Collections

Status: Production Ready ✅ Last Updated: 2025-11-07 Dependencies: None Latest Versions: @content-collections/[email protected], @content-collections/[email protected], [email protected]


What is Content Collections?

Content Collections transforms local content files (Markdown/MDX) into type-safe TypeScript data with automatic validation at build time.

Problem it solves: Manual content parsing, lack of type safety, runtime errors from invalid frontmatter.

How it works:

  1. Define collections in content-collections.ts (name, directory, Zod schema)
  2. CLI/plugin scans filesystem, parses frontmatter, validates against schema
  3. Generates TypeScript modules in .content-collections/generated/
  4. Import collections: import { allPosts } from "content-collections"

Perfect for: Blogs, documentation sites, content-heavy apps with Cloudflare Workers, Vite, Next.js.


Quick Start (5 Minutes)

1. Install Dependencies

pnpm add -D @content-collections/core @content-collections/vite zod

2. Configure TypeScript Path Alias

Add to tsconfig.json:

{
  "compilerOptions": {
    "paths": {
      "content-collections": ["./.content-collections/generated"]
    }
  }
}

  1. Configure Vite Plugin

Add to vite.config.ts:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import contentCollections from "@content-collections/vite";

export default defineConfig({
  plugins: [
    react(),
    contentCollections(), // MUST come after react()
  ],
});

4. Update .gitignore

.content-collections/

5. Create Collection Config

Create content-collections.ts in project root:

import { defineCollection, defineConfig } from "@content-collections/core";
import { z } from "zod";

const posts = defineCollection({
  name: "posts",
  directory: "content/posts",
  include: "*.md",
  schema: z.object({
    title: z.string(),
    date: z.string(),
    description: z.string(),
    content: z.string(),
  }),
});

export default defineConfig({
  collections: [posts],
});

6. Create Content Directory

mkdir -p content/posts

Create content/posts/first-post.md:

---
title: My First Post
date: 2025-11-07
description: Introduction to Content Collections
---

# My First Post

Content goes here...

7. Import and Use

import { allPosts } from "content-collections";

console.log(allPosts); // Fully typed!

Result: Type-safe content with autocomplete, validation, and HMR.


Critical Rules

✅ Always Do:

  1. Add path alias to tsconfig.json - Required for imports to work
  2. Add .content-collections to .gitignore - Generated files shouldn't be committed
  3. Use Standard Schema validators - Zod, Valibot, ArkType supported
  4. Include content field in schema - Required for frontmatter parsing
  5. Await compileMDX in transforms - MDX compilation is async
  6. Put contentCollections() after react() in Vite - Plugin order matters

❌ Never Do:

  1. Commit .content-collections directory - Always generated, never committed
  2. Use non-standard validators - Must support StandardSchema spec
  3. Forget to restart dev server after config changes - Required for new collections
  4. Use sync transforms with async operations - Transform must be async
  5. Double-wrap path alias - Use content-collections not ./content-collections
  6. Import from wrong package - @content-collections/core for config, content-collections for data

Known Issues Prevention

Issue #1: Module not found: 'content-collections'

Error: Cannot find module 'content-collections' or its corresponding type declarations

Why it happens: Missing TypeScript path alias configuration.

Prevention:

Add to tsconfig.json:

{
  "compilerOptions": {
    "paths": {
      "content-collections": ["./.content-collections/generated"]
    }
  }
}

Restart TypeScript server in VS Code: Cmd+Shift+P → "TypeScript: Restart TS Server"

Source: Common user error


Issue #2: Vite Constant Restart Loop

Error: Dev server continuously restarts, infinite loop.

Why it happens: Vite watching .content-collections directory changes, which triggers regeneration.

Prevention:

  1. Add to .gitignore:
.content-collections/
  1. Add to vite.config.ts (if still happening):
export default defineConfig({
  server: {
    watch: {
      ignored: ["**/.content-collections/**"],
    },
  },
});

Source: GitHub Issue #591 (TanStack Start)


Issue #3: Transform Types Not Reflected

Error: TypeScript types don't match transformed documents.

Why it happens: TypeScript doesn't automatically infer transform function return type.

Prevention:

Explicitly type your transform return:

const posts = defineCollection({
  name: "posts",
  // ... schema
  transform: (post): PostWithSlug => ({ // Type the return!
    ...post,
    slug: post._meta.path.replace(/\.md$/, ""),
  }),
});

type PostWithSlug = {
  // ... schema fields
  slug: string;
};

Source: GitHub Issue #396


Issue #4: Collection Not Updating on File Change

Error: New content files not appearing in collection.

Why it happens: Glob pattern doesn't match, or dev server needs restart.

Prevention:

  1. Verify glob pattern matches your files:
include: "*.md"        // Only root files
include: "**/*.md"     // All nested files
include: "posts/*.md"  // Only posts/ folder
  1. Restart dev server after adding new files outside watched patterns
  2. Check file actually saved (watch for editor issues)

Source: Common user error


Issue #5: MDX Type Errors with Shiki

Error: esbuild errors with shiki langAlias or compilation failures.

Why it happens: Version incompatibility between Shiki and Content Collections.

Prevention:

Use compatible versions:

{
  "devDependencies": {
    "@content-collections/mdx": "^0.2.2",
    "shiki": "^1.0.0"
  }
}

Check official compatibility matrix in docs before upgrading Shiki.

Source: GitHub Issue #598 (Next.js 15)


Issue #6: Custom Path Aliases in MDX Imports Fail

Error: MDX imports with @ alias don't resolve.

Why it happens: MDX compiler doesn't respect tsconfig path aliases.

Prevention:

Use relative paths in MDX imports:

<!-- ❌ Won't work -->
import Component from "@/components/Component"

<!-- ✅ Works -->
import Component from "../../components/Component"

Or configure files appender (advanced, see references/transform-cookbook.md).

Source: GitHub Issue #547


Issue #7: Unclear Validation Error Messages

Error: Cryptic Zod validation errors like "Expected string, received undefined".

Why it happens: Zod errors aren't formatted for content context.

Prevention:

Add custom error messages to schema:

schema: z.object({
  title: z.string({
    required_error: "Title is required in frontmatter",
    invalid_type_error: "Title must be a string",
  }),
  date: z.string().refine(
    (val) => !isNaN(Date.parse(val)),
    "Date must be valid ISO date (YYYY-MM-DD)"
  ),
})

Source: GitHub Issue #403


Issue #8: Ctrl+C Doesn't Stop Process

Error: Dev process hangs on exit, requires kill -9.

Why it happens: File watcher not cleaning up properly.

Prevention:

This is a known issue with the watcher. Workarounds:

  1. Use kill -9 <pid> when it hangs
  2. Use content-collections watch separately (not plugin) for more control
  3. Add cleanup handler in vite.config.ts (advanced)

Source: GitHub Issue #546


Configuration Patterns

Basic Blog Collection

import { defineCollection, defineConfig } from "@content-collections/core";
import { z } from "zod";

const posts = defineCollection({
  name: "posts",
  directory: "content/posts",
  include: "*.md",
  schema: z.object({
    title: z.string(),
    date: z.string(),
    description: z.string(),
    tags: z.array(z.string()).optional(),
    content: z.string(),
  }),
});

export default defineConfig({
  collections: [posts],
});

Multi-Collection Setup

const posts = defineCollection({
  name: "posts",
  directory: "content/posts",
  include: "*.md",
  schema: z.object({
    title: z.string(),
    date: z.string(),
    description: z.string(),
    content: z.string(),
  }),
});

const docs = defineCollection({
  name: "docs",
  directory: "content/docs",
  include: "**/*.md", // Nested folders
  schema: z.object({
    title: z.string(),
    category: z.string(),
    order: z.number().optional(),
    content: z.string(),
  }),
});

export default defineConfig({
  collections: [posts, docs],
});

Transform Functions (Computed Fields)

const posts = defineCollection({
  name: "posts",
  directory: "content/posts",
  include: "*.md",
  schema: z.object({
    title: z.string(),
    date: z.string(),
    content: z.string(),
  }),
  transform: (post) => ({
    ...post,
    slug: post._meta.path.replace(/\.md$/, ""),
    readingTime: Math.ceil(post.content.split(/\s+/).length / 200),
    year: new Date(post.date).getFullYear(),
  }),
});

MDX with React Components

import { compileMDX } from "@content-collections/mdx";

const posts = defineCollection({
  name: "posts",
  directory: "content/posts",
  include: "*.mdx",
  schema: z.object({
    title: z.string(),
    date: z.string(),
    content: z.string(),
  }),
  transform: async (post) => {
    const mdx = await compileMDX(post.content, {
      syntaxHighlighter: "shiki",
      shikiOptions: {
        theme: "github-dark",
      },
    });

    return {
      ...post,
      mdx,
      slug: post._meta.path.replace(/\.mdx$/, ""),
    };
  },
});

React Component Integration

Using Collections in React

import { allPosts } from "content-collections";

export function BlogList() {
  return (
    <ul>
      {allPosts.map((post) => (
        <li key={post._meta.path}>
          <h2>{post.title}</h2>
          <p>{post.description}</p>
          <time>{post.date}</time>
        </li>
      ))}
    </ul>
  );
}

Rendering MDX Content

import { MDXContent } from "@content-collections/mdx/react";

export function BlogPost({ post }: { post: { mdx: string } }) {
  return (
    <article>
      <MDXContent code={post.mdx} />
    </article>
  );
}

Cloudflare Workers Deployment

Content Collections is perfect for Cloudflare Workers because:

  • Build-time only (no runtime filesystem access)
  • Outputs static JavaScript modules
  • No Node.js dependencies in generated code

Deployment Pattern

Local Dev → content-collections build → vite build → wrangler deploy

wrangler.toml

name = "my-content-site"
compatibility_date = "2025-11-07"

[assets]
directory = "./dist"
binding = "ASSETS"

Build Script

package.json:

{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "deploy": "pnpm build && wrangler deploy"
  }
}

Note: Vite plugin handles content-collections build automatically!


Using Bundled Resources

Templates (templates/)

Copy-paste ready configuration files:

  • content-collections.ts - Basic blog setup
  • content-collections-multi.ts - Multiple collections
  • content-collections-mdx.ts - MDX with syntax highlighting
  • tsconfig.json - Complete TypeScript config
  • vite.config.ts - Vite plugin setup
  • blog-post.md - Example content file
  • BlogList.tsx - React list component
  • BlogPost.tsx - React MDX render component
  • wrangler.toml - Cloudflare Workers config

References (references/)

Deep-dive documentation for advanced topics:

  • schema-patterns.md - Common Zod schema patterns
  • transform-cookbook.md - Transform function recipes
  • mdx-components.md - MDX + React integration
  • deployment-guide.md - Cloudflare Workers setup

When to load: Claude should load these when you need advanced patterns beyond basic setup.

Scripts (scripts/)

  • init-content-collections.sh - One-command automated setup

Dependencies

Required

{
  "devDependencies": {
    "@content-collections/core": "^0.12.0",
    "@content-collections/vite": "^0.2.7",
    "zod": "^3.23.8"
  }
}

Optional (MDX)

{
  "devDependencies": {
    "@content-collections/markdown": "^0.1.4",
    "@content-collections/mdx": "^0.2.2",
    "shiki": "^1.0.0"
  }
}

Official Documentation


Package Versions (Verified 2025-11-07)

PackageVersionStatus
@content-collections/core0.12.0✅ Latest stable
@content-collections/vite0.2.7✅ Latest stable
@content-collections/mdx0.2.2✅ Latest stable
@content-collections/markdown0.1.4✅ Latest stable
zod3.23.8✅ Latest stable

Troubleshooting

Problem: TypeScript can't find 'content-collections'

Solution: Add path alias to tsconfig.json, restart TS server.


Problem: Vite keeps restarting

Solution: Add .content-collections/ to .gitignore and Vite watch ignore.


Problem: Changes not reflecting

Solution: Restart dev server, verify glob pattern, check file saved.


Problem: MDX compilation errors

Solution: Check Shiki version compatibility, verify MDX syntax.


Problem: Validation errors unclear

Solution: Add custom error messages to Zod schema.


Complete Setup Checklist

  • Installed @content-collections/core and @content-collections/vite
  • Installed zod for schema validation
  • Added path alias to tsconfig.json
  • Added contentCollections() to vite.config.ts (after react())
  • Added .content-collections/ to .gitignore
  • Created content-collections.ts in project root
  • Created content directory (e.g., content/posts/)
  • Defined collection with Zod schema
  • Created first content file with frontmatter
  • Imported collection in React component
  • Verified types work (autocomplete)
  • Tested hot reloading (change content file)

Questions? Issues?

  1. Check references/ directory for deep dives
  2. Verify path alias in tsconfig.json
  3. Check Vite plugin order (after react())
  4. Review known issues above
  5. Check official docs: https://www.content-collections.dev/docs

GitHub 仓库

jezweb/claude-skills
路径: skills/content-collections
aiautomationclaude-codeclaude-skillscloudflarereact

相关推荐技能