NuxtContentv3内容管理系统 nuxt-content

Nuxt Content v3 是一个基于 Git 的内容管理系统(CMS),专为 Nuxt.js 项目设计,用于管理 Markdown、YAML、JSON 和 CSV 文件,提供类型安全查询、模式验证(支持 Zod 和 Valibot)、全文本搜索、导航工具和 SQL 存储。适用于构建博客、文档网站、内容驱动应用等,支持 Cloudflare 和 Vercel 部署,集成 Nuxt Studio 进行生产编辑。关键词:Nuxt Content, Git CMS, Markdown 管理, 类型安全查询, 全文本搜索, 前端开发, 内容集合, 部署优化

前端开发 0 次安装 2 次浏览 更新于 3/7/2026

名称:nuxt-content 描述:Nuxt Content v3 是基于 Git 的内容管理系统,用于 Markdown/MDC 内容站点。适用于博客、文档、内容驱动应用,支持类型安全查询、模式验证(Zod/Valibot)、全文本搜索、导航工具。兼容 Nuxt Studio 生产编辑、Cloudflare D1/Pages 部署、Vercel 部署、SQL 存储、MDC 组件、内容集合。

关键词:nuxt content,@nuxt/content,内容集合,基于 git 的 cms,markdown cms,mdc 语法,nuxt studio,内容编辑,queryCollection,cloudflare d1 部署,vercel 部署,markdown 组件,prose 组件,内容导航,全文本搜索,类型安全查询,sql 存储,内容模式验证,zod 验证,valibot,远程仓库,内容查询,queryCollectionNavigation,queryCollectionSearchSections,ContentRenderer 组件 许可证:MIT

Nuxt Content v3

状态:生产就绪 最后更新:2025-01-10 依赖:无 最新版本:@nuxt/content@^3.0.0,nuxt-studio@^0.1.0-alpha,zod@^4.1.12,valibot@^0.42.0,better-sqlite3@^11.0.0


概述

Nuxt Content v3 是一个强大的基于 Git 的内容管理系统,用于 Nuxt 项目,通过 Markdown、YAML、JSON 和 CSV 文件管理内容。它将内容文件转换为结构化数据,提供类型安全查询、自动验证和基于 SQL 的存储以优化性能。

v3 的新特性

主要改进

  • 内容集合:结构化数据组织,支持类型安全查询、自动验证和高级查询构建器
  • 基于 SQL 的存储:生产环境使用 SQL(相比 v2 的大包大小)以优化查询和通用兼容性(服务器/无服务器/边缘/静态)
  • 完全 TypeScript 集成:自动为所有集合和 API 生成类型
  • 增强性能:通过适配器基 SQL 系统实现超快速数据检索
  • Nuxt Studio 集成:生产环境中自托管的 GitHub 同步内容编辑

何时使用此技能

使用此技能当:

  • 构建博客、文档站点或内容密集型应用
  • 使用 Markdown、YAML、JSON 或 CSV 文件管理内容
  • 实施基于 Git 的内容工作流
  • 创建类型安全的内容查询
  • 部署到 Cloudflare(Pages/Workers)或 Vercel
  • 使用 Nuxt Studio 设置生产内容编辑
  • 构建可搜索内容与全文本搜索
  • 从内容结构创建导航系统

快速开始(10分钟)

1. 安装 Nuxt Content

# Bun(推荐)
bun add @nuxt/content better-sqlite3

# npm
npm install @nuxt/content better-sqlite3

# pnpm
pnpm add @nuxt/content better-sqlite3

为何重要

  • @nuxt/content 是核心 CMS 模块
  • better-sqlite3 提供 SQL 存储以优化性能
  • 基本使用无需配置

2. 注册模块

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxt/content']
})

关键

  • 模块必须添加到 modules 数组(非 buildModules
  • 基本设置无需额外配置

3. 创建第一个集合

// content.config.ts
import { defineContentConfig, defineCollection } from '@nuxt/content'
import { z } from 'zod'

export default defineContentConfig({
  collections: {
    content: defineCollection({
      type: 'page',
      source: '**/*.md',
      schema: z.object({
        tags: z.array(z.string()).optional(),
        date: z.date().optional()
      })
    })
  }
})

创建内容文件:

<!-- content/index.md -->
---
标题:Hello World
描述:我的第一个 Nuxt Content 页面
标签:['nuxt', 'content']
---

# 欢迎使用 Nuxt Content v3

这是我的第一个内容驱动站点!

4. 查询和渲染内容

<!-- pages/[...slug].vue -->
<script setup>
const route = useRoute()
const { data: page } = await useAsyncData(route.path, () =>
  queryCollection('content').path(route.path).first()
)
</script>

<template>
  <ContentRenderer v-if="page" :value="page" />
</template>

查看完整模板templates/blog-collection-setup.ts


关键规则

始终要做

  1. 定义集合content.config.ts 中,然后再查询
  2. 使用 ISO 8601 日期格式2024-01-152024-01-15T10:30:00Z
  3. 重启开发服务器在更改 content.config.ts
  4. 使用 .only() 选择特定字段(性能优化)
  5. 放置 MDC 组件components/content/ 目录中
  6. 使用零填充前缀用于数字排序:01-02-
  7. 安装数据库连接器better-sqlite3 必需
  8. 指定语言在代码块中以启用语法高亮
  9. 使用 <!--more--> 在内容中分隔摘要
  10. D1 绑定必须为 “DB”(区分大小写)在 Cloudflare 上

永远不要做

  1. 不要在 content.config.ts 中定义集合前查询
  2. 不要使用非 ISO 日期格式(例如,“January 15, 2024”)
  3. 不要忘记重启开发服务器在配置更改后
  4. 不要查询所有字段当只需要部分时(使用 .only()
  5. 不要放置组件components/content/ 目录外
  6. 不要使用单数字前缀(使用 01- 而非 1-
  7. 不要跳过数据库连接器安装
  8. 不要忘记语言在代码围栏中
  9. 不要期望摘要没有 <!--more--> 分隔符
  10. 不要使用不同绑定名称对于 D1(必须为 “DB”)

内容集合

定义集合

集合组织相关内容与共享配置:

// content.config.ts
import { defineCollection, defineContentConfig } from '@nuxt/content'
import { z } from 'zod'

export default defineContentConfig({
  collections: {
    blog: defineCollection({
      type: 'page',
      source: 'blog/**/*.md',
      schema: z.object({
        title: z.string(),
        date: z.date(),
        tags: z.array(z.string()).default([])
      })
    }),

    authors: defineCollection({
      type: 'data',
      source: 'authors/*.yml',
      schema: z.object({
        name: z.string(),
        bio: z.string()
      })
    })
  }
})

集合类型

页面类型(type: 'page'

用于:映射到 URL 的内容

特性

  • 从文件结构自动生成路径
  • 内置字段:pathtitledescriptionbodynavigation
  • 完美用于:博客、文档、营销页面

路径映射

content/index.md        → /
content/about.md        → /about
content/blog/hello.md   → /blog/hello

数据类型(type: 'data'

用于:无 URL 的结构化数据

特性

  • 完整模式控制
  • 无自动路径生成
  • 完美用于:作者、产品、配置

模式验证

使用 Zod v4(推荐)

bun add -D zod@^4.1.12
# 或:npm install -D zod@^4.1.12
import { z } from 'zod'

schema: z.object({
  title: z.string(),
  date: z.date(),
  published: z.boolean().default(false),
  tags: z.array(z.string()).optional(),
  category: z.enum(['news', 'tutorial', 'update'])
})

使用 Valibot(替代)

bun add -D valibot@^0.42.0
# 或:npm install -D valibot@^0.42.0
import * as v from 'valibot'

schema: v.object({
  title: v.string(),
  date: v.date(),
  published: v.boolean(false),
  tags: v.optional(v.array(v.string()))
})

查询内容

基本查询

// 获取所有文章
const posts = await queryCollection('blog').all()

// 通过路径获取单篇文章
const post = await queryCollection('blog').path('/blog/hello').first()

// 通过 ID 获取文章
const post = await queryCollection('blog').where('_id', '=', 'hello').first()

字段选择

// 选择特定字段(性能优化)
const posts = await queryCollection('blog')
  .only(['title', 'description', 'date', 'path'])
  .all()

// 排除字段
const posts = await queryCollection('blog')
  .without(['body'])
  .all()

条件查询

// 单条件
const posts = await queryCollection('blog')
  .where('published', '=', true)
  .all()

// 多条件
const posts = await queryCollection('blog')
  .where('published', '=', true)
  .where('category', '=', 'tutorial')
  .all()

// 操作符:=, !=, <, <=, >, >=, in, not-in, like
const recent = await queryCollection('blog')
  .where('date', '>', new Date('2024-01-01'))
  .all()

const tagged = await queryCollection('blog')
  .where('tags', 'in', ['nuxt', 'vue'])
  .all()

排序和分页

// 按字段排序
const posts = await queryCollection('blog')
  .sort('date', 'DESC')
  .all()

// 分页
const posts = await queryCollection('blog')
  .sort('date', 'DESC')
  .limit(10)
  .offset(0)
  .all()

计数

// 计数结果
const total = await queryCollection('blog')
  .where('published', '=', true)
  .count()

服务器端查询

// server/api/posts.get.ts
export default defineEventHandler(async (event) => {
  const posts = await queryCollection('blog')
    .where('published', '=', true)
    .sort('date', 'DESC')
    .all()

  return { posts }
})

导航

从内容结构自动生成导航树:

const navigation = await queryCollectionNavigation('blog').all()

返回层级结构

[
  {
    title: '入门指南',
    path: '/docs/getting-started',
    children: [{ title: '安装', path: '/docs/getting-started/installation' }]
  }
]

高级模式(过滤、排序、自定义结构):参见 references/collection-examples.md


MDC 语法(Markdown 组件)

基本组件语法

<!-- 默认插槽 -->
::my-alert
这是一个警告消息
::

<!-- 命名插槽 -->
::my-card
#title
卡片标题
#default
卡片内容在此
::

组件

<!-- components/content/MyAlert.vue -->
<template>
  <div class="alert">
    <slot />
  </div>
</template>

属性

::my-button{href="/docs" type="primary"}
点击我
::

组件

<!-- components/content/MyButton.vue -->
<script setup>
defineProps<{
  href: string
  type: 'primary' | 'secondary'
}>()
</script>

全文本搜索

// 搜索所有内容
const results = await queryCollectionSearchSections('blog', 'nuxt content')
  .where('published', '=', true)
  .all()

返回

[
  {
    id: 'hello',
    path: '/blog/hello',
    title: 'Hello World',
    content: '...匹配文本...'
  }
]

部署

Cloudflare Pages + D1

bun add -D @nuxthub/core
bunx wrangler d1 create nuxt-content
bun run build && bunx wrangler pages deploy dist

wrangler.toml

[[d1_databases]]
binding = "DB"  # 必须精确为 "DB"(区分大小写)
database_name = "nuxt-content"
database_id = "你的数据库id"

关键:D1 绑定名称必须为 DB(区分大小写)。

参见references/deployment-checklists.md 获取完整的 Cloudflare 部署指南与故障排除。


Vercel

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxt/content'],
  routeRules: {
    '/blog/**': { prerender: true }
  }
})
vercel deploy

参见references/deployment-checklists.md 获取完整的 Vercel 配置和预渲染策略。


Nuxt Studio 集成

启用 Studio

bun add -D nuxt-studio@alpha
# 或:npm install -D nuxt-studio@alpha
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxt/content', 'nuxt-studio'],
  
  studio: {
    enabled: true,
    gitInfo: {
      name: '你的名字',
      email: '你的邮箱@example.com'
    }
  }
})

OAuth 设置

  1. 创建 GitHub OAuth 应用
  2. 设置授权回调 URL:https://yourdomain.com/api/__studio/oauth/callback
  3. 添加客户端 ID 和密钥到环境变量

关键:回调 URL 必须完全匹配生产域名(包括 https://)。


前5个关键问题

问题 #1:集合未找到

错误集合 'xyz' 未找到

解决方案:在 content.config.ts 中定义集合并重启开发服务器

rm -rf .nuxt && bun dev

问题 #2:日期验证失败

错误验证错误:期望日期,接收到字符串

解决方案:使用 ISO 8601 格式:

---
date: 2024-01-15  # ✅ 正确
# 非:"January 15, 2024"  # ❌ 错误
---

问题 #3:D1 绑定未找到(Cloudflare)

错误DB 未定义

解决方案:D1 绑定名称在 Cloudflare 仪表板中必须精确为 DB(区分大小写)。


问题 #4:MDC 组件未渲染

错误:组件显示为原始文本

解决方案:将组件放置在 components/content/ 目录中,名称精确匹配:

<!-- components/content/MyAlert.vue -->
::my-alert
内容
::

问题 #5:导航未更新

错误:新内容未出现在导航中

解决方案:清除 .nuxt 缓存:

rm -rf .nuxt && bun dev

参见所有18个问题references/error-catalog.md


何时加载参考文档

加载 references/error-catalog.md

  • 用户遇到超出前5个问题所示的错误
  • 调试集合验证、模式错误或部署问题
  • 需要完整的错误目录,包含所有18个文档化解决方案和来源

加载 references/collection-examples.md

  • 设置高级集合类型(数据 vs 页面)
  • 实施复杂模式验证模式
  • 需要 Zod v4 或 Valibot 模式示例
  • 处理多个集合配置

加载 references/query-operators.md

  • 构建超越基本示例的复杂查询
  • 需要所有操作符的完整参考(=, !=, <, >, <=, >=, in, not-in, like)
  • 实施分页、排序或字段选择
  • 故障排除查询语法错误

加载 references/deployment-checklists.md

  • 部署到特定平台(Cloudflare Pages、Cloudflare Workers D1、Vercel)
  • 设置生产环境配置
  • 故障排除部署特定错误(D1 绑定、预渲染路由)
  • 需要平台特定的 wrangler.toml 或 vercel.json 示例

加载 references/mdc-syntax-reference.md

  • 实施自定义 MDC(Markdown 组件)
  • 调试组件渲染问题
  • 需要完整的属性、插槽、嵌套语法参考
  • 创建高级内容组件

加载 references/studio-setup-guide.md

  • 为生产内容编辑设置 Nuxt Studio
  • 配置 GitHub OAuth 认证
  • 启用自托管内容编辑与 GitHub 同步
  • 故障排除 Studio 认证或 Git 同步问题

模板templates/):

  • blog-collection-setup.ts - 完整的博客设置,包括集合、查询、导航、搜索和部署(334行)

性能提示

  1. 使用 .only() 选择特定字段
  2. 启用缓存用于生产
  3. 使用分页用于大型集合
  4. 预渲染静态路由在 Vercel 上
  5. 使用 SQL 存储(better-sqlite3)以优化性能

最佳实践

  1. 始终先定义集合并再查询
  2. 使用 TypeScript 进行类型安全查询
  3. 使用 Zod 或 Valibot 验证模式
  4. 将 MDC 组件放置在 components/content/ 目录中
  5. 使用 ISO 8601 日期格式
  6. 添加 <!--more--> 用于摘要
  7. 在代码块中指定语言
  8. 配置更改后清除 .nuxt 缓存
  9. 对于 Cloudflare:D1 绑定必须为 “DB”
  10. 使用分页用于大型数据集

与其他技能的集成

此技能可与以下技能良好组合:

  • nuxt-v4 → 核心 Nuxt 框架
  • nuxt-ui-v4 → UI 组件库
  • cloudflare-worker-base → Cloudflare 部署
  • tailwind-v4-shadcn → 样式
  • drizzle-orm-d1 → 额外数据库查询
  • cloudflare-d1 → 数据库集成

额外资源

官方文档

示例


生产测试:文档站点、博客、内容平台 最后更新:2025-01-27 令牌节省:约60%(减少内容 + 错误文档)