Nuxt Studio 升级开发规划
背景
当前项目已经升级到 Nuxt 4、Nuxt Content v3 与 pnpm 11,内容系统采用 content/docs 和 content/blog 两个集合,站点支持文档、博客、RSS、Atom、sitemap、robots、OG 图片与静态生成。
本次规划目标是在现有内容体系上接入 Nuxt Studio,让内容编辑者可以在浏览器中编辑 Markdown、frontmatter、MDC 组件和媒体资源,并通过 GitHub 提交内容变更。
参考官方文档:
核心结论
Nuxt Studio 不是一个纯静态后台页面。生产环境中的登录、鉴权、Git 提交和发布流程依赖服务端路由,因此官方要求部署在支持 SSR 的平台上,并使用 nuxt build 生成生产产物。
当前项目的 GitHub Actions 主要执行 pnpm run generate,再将 .output/public 通过 rsync 上传为静态站点。这个部署模式无法完整承载 Nuxt Studio。
推荐路线是将主站升级为 SSR/hybrid 部署:
- 继续对
/、/docs/**、/blog/**等内容页执行 prerender。 - 生产运行
.output/server/index.mjs。 - Studio 管理界面挂载在
/_studio或/admin。 - 使用 GitHub OAuth 登录,并由 Nuxt Studio 将内容变更提交到 GitHub 仓库。
当前项目适配点
已具备条件
- 项目已使用 Nuxt 4 与 Nuxt Content v3。
content.config.ts已定义docs和blog两个 collection。- 内容文件以 Markdown 为主,适合 Studio 编辑。
- 已有 Docker SSR 构建路线,Dockerfile 运行
pnpm build并启动.output/server/index.mjs。 - 已有
content:check脚本,可作为 Studio 发布后的内容质量守门。
需要先处理的问题
- Dockerfile 需要复制
pnpm-workspace.yaml
当前 pnpm 11 的构建脚本审批配置位于pnpm-workspace.yaml。如果 Docker deps stage 只复制package.json、pnpm-lock.yaml和.npmrc,better-sqlite3的原生构建许可可能不会进入容器安装环境。 - CI/CD 需要从纯静态部署调整为 SSR/hybrid
Studio 生产编辑依赖服务端路由,不能只上传.output/public。需要将部署目标切换为 Node SSR 或 Docker 服务。 - Content schema 需要更适合 Studio 表单
当前 schema 运行时可用,但对 Studio 的编辑体验不够明确。应显式声明title、description、navigation、img、date、links等字段,并为 media、icon、textarea 等输入类型提供编辑器提示。 - CSP 需要为 Studio 单独验证
当前全站启用严格 CSP。Studio 可能涉及浏览器侧 SQLite、IndexedDB、media draft service worker、外部 OAuth 跳转等能力。接入后需要对/_studio/**与/__nuxt_studio/**做浏览器实测,必要时单独放宽 route rules。
推荐架构
实施阶段
阶段一:部署基础调整
目标:让项目具备稳定的 SSR/hybrid 生产部署能力。
任务:
- 修改 Dockerfile deps stage,复制
pnpm-workspace.yaml。 - 将 CI 构建命令从单纯
pnpm run generate调整为pnpm build。 - 部署
.output/server,生产运行node .output/server/index.mjs。 - 保留现有 prerender 设置,让公开内容页仍然静态化输出。
- 确认微信签名服务、RSS、Atom、sitemap、robots 在 SSR 模式下行为一致。
验收:
pnpm install --frozen-lockfile通过。pnpm build通过。- Docker 镜像构建通过。
- 生产环境能访问首页、文档页、博客页、RSS、Atom、sitemap、robots。
阶段二:接入 Nuxt Studio 模块
目标:本地与生产环境能打开 Studio 管理界面。
任务:
- 安装
nuxt-studio。 - 在
nuxt.config.ts的modules中加入nuxt-studio。 - 配置 Studio 路由,建议先使用默认
/_studio。 - 配置 GitHub 仓库信息:
studio: {
route: '/_studio',
repository: {
provider: 'github',
owner: 'estel-li',
repo: 'estel_docs',
branch: 'main',
private: false
},
git: {
commit: {
messagePrefix: 'content:'
}
},
editor: {
iconLibraries: ['lucide', 'simple-icons', 'vscode-icons', 'devicon']
}
}
验收:
- 本地开发环境能打开
/_studio。 - 生产构建包含 Studio 路由。
- 不影响现有 docs/blog 页面渲染。
阶段三:配置 GitHub OAuth
目标:编辑者可通过 GitHub 登录 Studio,并将内容变更发布到仓库。
GitHub OAuth App 建议配置:
Homepage URL:
https://lijue.net
Authorization callback URL:
https://lijue.net/__nuxt_studio/auth/github
生产环境变量:
NUXT_STUDIO_AUTH_GITHUB_CLIENT_ID=...
NUXT_STUDIO_AUTH_GITHUB_CLIENT_SECRET=...
NUXT_STUDIO_AUTH_GITHUB_MODERATORS=editor@example.com,admin@example.com
说明:
- GitHub OAuth 登录后可以自动用于 Git 操作,不需要额外 Personal Access Token。
- 即使官方将 GitHub moderators 标为可选,也建议配置白名单,避免编辑入口过宽。
- 不建议第一阶段使用 Google OAuth,因为 Google 登录不能直接提供 Git 写入能力,仍需单独配置 Git token。
验收:
- 生产环境能完成 GitHub OAuth 登录。
- 非白名单用户不能进入编辑流程。
- 白名单用户能编辑内容并发布。
- GitHub 仓库出现以
content:开头的提交。
阶段四:优化 Content Schema
目标:让 Studio 自动生成更清晰的 frontmatter 表单。
任务:
- 将
z从@nuxt/contentre-export 改为zod/v4。 - 显式定义
title、description、navigation、links、draft等字段。 - 为博客集合定义
img、date、updated、category、tags。 - 对适合可视化编辑的字段使用
property()提供编辑器提示。
示例方向:
import { defineCollection, defineContentConfig, property } from '@nuxt/content'
import { z } from 'zod/v4'
const linkSchema = z.object({
label: z.string(),
icon: z.string(),
to: z.string(),
target: z.string().optional()
})
const navigationSchema = z.union([
z.boolean(),
z.object({
title: z.string().optional(),
description: z.string().optional(),
icon: property(z.string()).editor({ input: 'icon' }).optional()
})
])
博客 img 字段有两种路线:
- 若继续使用远程图床,保留普通
z.string()。 - 若希望 Studio 管理
/public媒体库,改为 media editor,并逐步把图片迁入public或外部 media provider。
验收:
- Studio 中 docs/blog frontmatter 表单清晰可编辑。
- 新建博客时能看到必填字段。
pnpm content:check能继续校验内容质量。
阶段五:接入自定义 MDC 组件编辑
目标:让编辑者可以在 Studio 中插入项目已有的内容组件。
任务:
- 将
app/components/content下的 MDC 内容组件标记为全局组件。 - 通过 Studio editor 配置限制可用组件范围。
- 为常用组件补充 props 类型,方便 Studio 生成编辑面板。
建议先开放:
ECardETabsStackPlaygroundFileTreeCodeTreeButtonLinkSmartIconReadMore
暂不开放:
- 布局组件
- 导航组件
- 仅用于页面壳层的业务组件
- 依赖复杂运行时状态的组件
验收:
- Studio slash menu 可插入常用内容组件。
- 插入组件后 Markdown 源码可读。
- 构建与渲染正常。
阶段六:强化 CI 守门
目标:Studio 发布内容后,自动发现错误内容。
建议 CI 至少执行:
pnpm install --frozen-lockfile
pnpm content:check
pnpm typecheck
pnpm test:unit
pnpm build
可选增强:
- 对 PR 运行
pnpm test:e2e。 - 对 main 定期运行完整 E2E。
- 将内容检查结果作为 GitHub status check。
验收:
- Studio 发布错误 frontmatter 时 CI 能失败。
- Studio 发布坏链接或坏图片引用时 CI 能失败。
- main 分支始终保持可部署。
风险与对策
纯静态部署不兼容 Studio 生产编辑
风险:只部署 .output/public 会导致登录、发布、Git 写入等功能不可用。
对策:切换为 SSR/hybrid 部署,保留 prerender 优势。
内容编辑者可能破坏文件命名约定
风险:当前内容依赖数字前缀控制排序,例如 1.简单文档/2.installation.md。Studio 编辑者如果随意重命名文件,可能影响路由和导航顺序。
对策:在编辑规范中明确文件命名规则;首阶段仅允许编辑现有文件,谨慎开放新建与重命名能力。
远程图床与 Studio Media Library 体验不一致
风险:当前博客大量使用远程图片 URL。Studio Media Library 默认管理 /public,不能天然管理外部图床。
对策:第一阶段保留远程 URL;第二阶段评估接入 S3、R2 或继续使用现有图床。
CSP 影响 Studio 管理界面
风险:严格 CSP 可能拦截 Studio 的 worker、blob、OAuth 或媒体预览能力。
对策:为 Studio 路由单独配置 routeRules,并用浏览器 E2E 实测登录、编辑、发布和媒体上传。
最小可行版本
MVP 范围:
- SSR/hybrid 部署可用。
/_studio可登录。- GitHub OAuth 可鉴权。
- 白名单编辑者可编辑现有 docs/blog Markdown。
- 发布后 GitHub 产生 commit。
- CI 自动构建并部署。
- 不开放复杂媒体管理和大规模组件库。
不在 MVP 范围:
- 多角色权限系统。
- 自定义工作流审批。
- 外部媒体存储迁移。
- 多分支草稿预览。
- 与微信签名服务联动。
最终验收清单
pnpm install --frozen-lockfile通过。pnpm content:check通过。pnpm typecheck通过。pnpm test:unit通过。pnpm build通过。- Docker 构建通过。
- 生产
/_studio可打开。 - GitHub OAuth 登录成功。
- 非授权用户无法编辑。
- 授权用户可编辑 docs 页面并发布。
- 授权用户可编辑 blog frontmatter 并发布。
- 自定义 MDC 组件可插入并渲染。
- 发布后 GitHub 产生内容提交。
- CI 自动部署成功。
- 首页、文档、博客、RSS、Atom、sitemap、robots 行为正常。
推荐落地顺序
- 修复 Dockerfile pnpm workspace 复制问题。
- 将部署链路切换到 SSR/hybrid。
- 安装并启用
nuxt-studio。 - 配置 GitHub OAuth 与 moderators。
- 优化
content.config.tsschema。 - 开放第一批内容组件给 Studio。
- 恢复并强化 CI 内容质量检查。
- 生产环境小范围试用。
- 根据编辑体验再迭代媒体库、组件属性和权限策略。