content-collections について
content-collections は、ローカルの Markdown と MDX ファイルを検証済みの型付き TypeScript データに変換します。コンテンツの多いサイト向けに、ビルド時のモジュール生成、スキーマ検証、変換処理を提供します。
主な機能
- 01Markdown と MDX の解析
- 02ビルド時のスキーマ検証
- 03型付き TypeScript モジュール生成
- 04コレクションの変換処理
- 05Vite プラグイン連携
- 06MDX コンパイル対応
活用シーン
- 01型付きブログ記事コレクションの構築
- 02ビルド時の frontmatter 検証
- 03Vite サイトでのローカルコンテンツ利用
- 04React での MDX コンテンツ表示
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jackspace/ claudeskillz --skill content-collectionsインストール後、Claude Code で/content-collectionsを入力して読み込まれたか確認します。
同梱ファイルREADME.mdSKILL.json
詳細
コンテンツコレクション
ステータス:本番環境で使用可能 ✅ 最終更新日:2025-11-07 依存関係:なし 最新バージョン:@content-collections/[email protected]、@content-collections/[email protected]、[email protected]
Content Collections とは?
Content Collections は、ローカルのコンテンツファイル(Markdown/MDX)を、ビルド時に自動検証される型安全な TypeScript データに変換します。
解決する問題:手動でのコンテンツ解析、型安全性の欠如、無効なフロントマターによるランタイムエラー。
仕組み:
content-collections.tsでコレクションを定義します(名前、ディレクトリ、Zod スキーマ)- CLI/プラグインがファイルシステムをスキャンし、フロントマターを解析して、スキーマに照らして検証します
.content-collections/generated/に TypeScript モジュールを生成します- コレクションをインポートします:
import { allPosts } from "content-collections"
最適な用途:ブログ、ドキュメントサイト、Cloudflare Workers、Vite、Next.js を使用するコンテンツ中心のアプリ。
クイックスタート(5 分)
1. 依存関係をインストールする
pnpm add -D @content-collections/core @content-collections/vite zod
2. TypeScript のパスエイリアスを設定する
tsconfig.json に追加します:
{
"compilerOptions": {
"paths": {
"content-collections": ["./.content-collections/generated"]
}
}
}
- Vite プラグインを設定する
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. .gitignore を更新する
.content-collections/
5. コレクション設定を作成する
プロジェクトのルートに content-collections.ts を作成します:
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. コンテンツディレクトリを作成する
mkdir -p content/posts
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 { allPosts } from "content-collections";
console.log(allPosts); // Fully typed!
結果:自動補完、検証、HMR に対応した型安全なコンテンツを利用できます。
重要なルール
✅ 必ず行うこと:
- tsconfig.json にパスエイリアスを追加する - インポートを機能させるために必要です
- .content-collections を .gitignore に追加する - 生成ファイルはコミットしないでください
- Standard Schema バリデーターを使用する - Zod、Valibot、ArkType に対応しています
- スキーマに
contentフィールドを含める - フロントマターの解析に必要です - 変換処理で compileMDX を await する - MDX のコンパイルは非同期です
- Vite では contentCollections() を react() の後に配置する - プラグインの順序が重要です
❌ 絶対にしないこと:
- .content-collections ディレクトリをコミットする - 常に生成されるため、コミットしないでください
- 標準以外のバリデーターを使用する - StandardSchema 仕様への対応が必要です
- 設定変更後に開発サーバーを再起動し忘れる - 新しいコレクションを認識させるために必要です
- 非同期処理で同期変換を使用する - 変換処理は非同期である必要があります
- パスエイリアスを二重にラップする -
./content-collectionsではなくcontent-collectionsを使用してください - 誤ったパッケージからインポートする - 設定には
@content-collections/core、データにはcontent-collectionsを使用します
既知の問題を防ぐ
問題 #1:モジュールが見つかりません:'content-collections'
エラー:Cannot find module 'content-collections' or its corresponding type declarations
原因:TypeScript のパスエイリアス設定がありません。
予防策:
tsconfig.json に追加します:
{
"compilerOptions": {
"paths": {
"content-collections": ["./.content-collections/generated"]
}
}
}
VS Code で TypeScript サーバーを再起動します:Cmd+Shift+P → "TypeScript: Restart TS Server"
出典:よくあるユーザーエラー
問題 #2:Vite が連続して再起動する
エラー:開発サーバーが無限ループで再起動し続けます。
原因:Vite が .content-collections ディレクトリの変更を監視しており、再生成が引き起こされています。
予防策:
.gitignoreに追加します:
.content-collections/
- (問題が続く場合)
vite.config.tsに追加します:
export default defineConfig({
server: {
watch: {
ignored: ["**/.content-collections/**"],
},
},
});
出典:GitHub Issue #591(TanStack Start)
問題 #3:変換後の型が反映されない
エラー:TypeScript の型が変換後のドキュメントと一致しません。
原因:TypeScript は変換関数の戻り値の型を自動的に推論しません。
予防策:
変換処理の戻り値の型を明示的に指定します:
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;
};
出典:GitHub Issue #396
問題 #4:ファイル変更時にコレクションが更新されない
エラー:新しいコンテンツファイルがコレクションに表示されません。
原因:Glob パターンが一致していないか、開発サーバーの再起動が必要です。
予防策:
- Glob パターンがファイルと一致することを確認します:
include: "*.md" // Only root files
include: "**/*.md" // All nested files
include: "posts/*.md" // Only posts/ folder
- 監視対象のパターン外に新しいファイルを追加した場合は、開発サーバーを再起動します
- ファイルが実際に保存されていることを確認します(エディターの問題に注意してください)
出典:よくあるユーザーエラー
Issue #5:Shiki による MDX の型エラー
エラー:esbuild errors with shiki langAlias またはコンパイルエラーが発生します。
原因:Shiki と Content Collections のバージョンに互換性がありません。
予防策:
互換性のあるバージョンを使用してください。
{
"devDependencies": {
"@content-collections/mdx": "^0.2.2",
"shiki": "^1.0.0"
}
}
Shiki をアップグレードする前に、ドキュメントで公式の互換性マトリクスを確認してください。
出典:GitHub Issue #598(Next.js 15)
Issue #6:MDX インポートでカスタムパスエイリアスが機能しない
エラー:@ エイリアスを使った MDX インポートを解決できません。
原因:MDX コンパイラーは tsconfig のパスエイリアスを認識しません。
予防策:
MDX インポートでは相対パスを使用してください。
import Component from "@/components/Component"
import Component from "../../components/Component"
または、files appender を設定してください(上級者向け。references/transform-cookbook.md を参照)。
出典:GitHub Issue #547
Issue #7:検証エラーメッセージがわかりにくい
エラー:「Expected string, received undefined」のような、わかりにくい Zod 検証エラーが発生します。
原因:Zod エラーはコンテンツのコンテキストに合わせてフォーマットされていません。
予防策:
スキーマにカスタムエラーメッセージを追加してください。
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)"
),
})
出典:GitHub Issue #403
Issue #8:Ctrl+C でプロセスが停止しない
エラー:開発プロセスが終了時にハングし、kill -9 が必要になります。
原因:ファイルウォッチャーが適切にクリーンアップされません。
予防策:
これはウォッチャーの既知の問題です。回避策は次のとおりです。
- ハングした場合は
kill -9 <pid>を使用する - より細かく制御するには、プラグインではなく
content-collections watchを単独で使用する vite.config.tsにクリーンアップハンドラーを追加する(上級者向け)
出典:GitHub Issue #546
設定パターン
基本的なブログコレクション
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],
});
複数コレクションの設定
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],
});
変換関数(計算フィールド)
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(),
}),
});
React コンポーネントを使用した MDX
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 コンポーネントとの統合
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>
);
}
MDX コンテンツをレンダリングする
import { MDXContent } from "@content-collections/mdx/react";
export function BlogPost({ post }: { post: { mdx: string } }) {
return (
<article>
<MDXContent code={post.mdx} />
</article>
);
}
Cloudflare Workers へのデプロイ
Content Collections は、次の理由から Cloudflare Workers に最適です。
- ビルド時のみ動作します(実行時のファイルシステムアクセスは不要です)
- 静的な JavaScript モジュールを出力します
- 生成されたコードに Node.js の依存関係はありません
デプロイパターン
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"
ビルドスクリプト
package.json:
{
"scripts": {
"dev": "vite",
"build": "vite build",
"deploy": "pnpm build && wrangler deploy"
}
}
注:Vite プラグインが content-collections build を自動的に処理します。
バンドルされたリソースの使用
テンプレート(templates/)
コピーしてすぐに使える設定ファイルです。
content-collections.ts- 基本的なブログの設定content-collections-multi.ts- 複数コレクションの設定content-collections-mdx.ts- シンタックスハイライトを使用した MDXtsconfig.json- TypeScript の完全な設定vite.config.ts- Vite プラグインの設定blog-post.md- コンテンツファイルの例BlogList.tsx- React のリストコンポーネントBlogPost.tsx- React の MDX レンダリングコンポーネントwrangler.toml- Cloudflare Workers の設定
リファレンス(references/)
高度なトピックを詳しく解説するドキュメントです。
schema-patterns.md- よく使われる Zod スキーマのパターンtransform-cookbook.md- 変換関数のレシピmdx-components.md- MDX と React の統合deployment-guide.md- Cloudflare Workers の設定
読み込みのタイミング:基本的な設定を超える高度なパターンが必要な場合、Claude がこれらを読み込みます。
スクリプト(scripts/)
init-content-collections.sh- 1 つのコマンドで自動セットアップ
依存関係
必須
{
"devDependencies": {
"@content-collections/core": "^0.12.0",
"@content-collections/vite": "^0.2.7",
"zod": "^3.23.8"
}
}
オプション(MDX)
{
"devDependencies": {
"@content-collections/markdown": "^0.1.4",
"@content-collections/mdx": "^0.2.2",
"shiki": "^1.0.0"
}
}
公式ドキュメント
- 公式サイト:https://www.content-collections.dev
- ドキュメント:https://www.content-collections.dev/docs
- GitHub:https://github.com/sdorra/content-collections
- Vite プラグイン:https://www.content-collections.dev/docs/vite
- MDX 統合:https://www.content-collections.dev/docs/mdx
パッケージのバージョン(2025-11-07 検証済み)
| パッケージ | バージョン | ステータス |
|---|---|---|
| @content-collections/core | 0.12.0 | ✅ 最新の安定版 |
| @content-collections/vite | 0.2.7 | ✅ 最新の安定版 |
| @content-collections/mdx | 0.2.2 | ✅ 最新の安定版 |
| @content-collections/markdown | 0.1.4 | ✅ 最新の安定版 |
| zod | 3.23.8 | ✅ 最新の安定版 |
トラブルシューティング
問題:TypeScript が 'content-collections' を見つけられない
解決策:tsconfig.json にパスエイリアスを追加し、TS サーバーを再起動します。
問題:Vite が再起動を繰り返す
解決策:.content-collections/ を .gitignore と Vite の監視対象から除外する設定に追加します。
問題:変更が反映されない
解決策:開発サーバーを再起動し、glob パターンを確認して、ファイルが保存されていることを確かめます。
問題:MDX のコンパイルエラー
解決策:Shiki のバージョンとの互換性を確認し、MDX の構文を検証します。
問題:バリデーションエラーの内容がわかりにくい
解決策:Zod スキーマにカスタムエラーメッセージを追加します。
セットアップの完全なチェックリスト
-
@content-collections/coreと@content-collections/viteをインストールした - スキーマの検証用に
zodをインストールした -
tsconfig.jsonにパスエイリアスを追加した -
vite.config.tsにcontentCollections()を追加した(react() の後) -
.content-collections/を.gitignoreに追加した - プロジェクトのルートに
content-collections.tsを作成した - コンテンツディレクトリ(例:
content/posts/)を作成した - Zod スキーマでコレクションを定義した
- frontmatter を含む最初のコンテンツファイルを作成した
- React コンポーネントでコレクションをインポートした
- 型が機能することを確認した(自動補完)
- ホットリロードをテストした(コンテンツファイルを変更)
質問や問題がありますか?
- 詳細な解説については
references/ディレクトリを確認してください - tsconfig.json のパスエイリアスを確認してください
- Vite プラグインの順序を確認してください(react() の後)
- 上記の既知の問題を確認してください
- 公式ドキュメントを確認してください:https://www.content-collections.dev/docs