Serenade 是一个基于 Nuxt 的博客 / 知识库 / 朋友圈系统:内容用 Markdown(与少量 JSON)保存,页面可以静态导出,也可以用 Node 运行;同时也提供一套可选的 AI 写作脚手架,用来生成 URL slug 与封面图。
很多争论其实都混在一起:要不要服务器、要不要数据库、要不要反复编译。
Serenade 的选择很明确:
- 静:内容永远是文件(
content/),不依赖数据库 - 动:在 Node 运行时读取这些文件,SSR 渲染页面,并提供搜索、RSS 等能力
- 合:同一套内容结构,既能
build跑服务,也能generate导出静态
| 你在乎的事 | 静态导出(nuxt generate) |
Node 运行(nuxt build) |
|---|---|---|
| 服务器 | 不需要(静态托管即可) | 需要(Node 进程) |
| 数据库 | 不需要 | 不需要 |
| 内容更新 | 重新 generate | 同步 content/ 即可 |
| 运行时能力 | 受限 | 完整 |
| 适合场景 | 低维护、纯静态 | 频繁更新、需要动态能力 |
你可以把它理解成一句宣传语:
内容是静的,发布是自由的。
- 构建一次,内容常新(Node 模式):文章/友链/项目更新只需要同步
content/ - 0 数据库:Markdown 天然适合 Git 管理,迁移与备份都轻
- 博客 + 知识库 + 朋友圈:文章、VuePress 风格专栏、友链与 RSS 订阅聚合、项目展示
- AI 写作脚手架(可选):生成 URL slug、生成文章封面,把重复劳动交给机器
- 同构体验:既可静态托管,也可 SSR 运行
- 文章系统:
content/posts/<slug>/README.md - 专栏/知识库:
content/columns/<slug>/ - 标签聚合:从 front-matter 统计
- 全文搜索:服务端搜索 API
- 友链 / 朋友圈:
content/friends.json+ RSS 拉取 - 项目展示:
content/projects.json - 数学公式:KaTeX
- UI:TailwindCSS、暗黑模式、响应式布局
pnpm install
pnpm dev访问:http://localhost:3000
每次 push 到 main 分支会自动构建并推送镜像到 GHCR。
# 创建 content 目录并放入你的内容
mkdir -p content
# 启动
docker compose up -d更新镜像:
docker compose pull && docker compose up -d- 默认监听
3000,可用SERENADE_PORT=8080 docker compose up -d映射到其它端口 docker-compose.yml把宿主机./content挂载进容器,内容更新后刷新即可生效- 站点信息通过
.env中的SITE_*环境变量配置,不再把个人站点配置写死到预构建镜像
如果你 fork 了项目或做了自定义修改,可以本地构建:
docker build -t serenade:local .
docker run -d -p 3000:3000 -v ./content:/app/content --name serenade serenade:localpnpm build
# 上传 .output/ 与 content/ 到服务器
node .output/server/index.mjs后续更新内容:只同步 content/,无需重新 build。
项目内置 npm run sync(Windows 使用 scp,Linux/Mac 使用 rsync)同步 content/。
pnpm generate
# 部署 .output/public 到任意静态托管本地静态调试:
py -m http.server 4173 --directory .output/public访问:http://localhost:4173/feed
- 更新内容需要重新
generate(可交给 CI 自动化)
content/
posts/
<post-slug>/
README.md
cover.png (可选)
columns/
<column-slug>/
README.md
<chapter>.md
friends.json
projects.json
npm run new:post:创建文章(可选 AI 生成 URL / 配图)npm run new:column:创建专栏npm run sync:同步到服务器(支持同步content/、.output/、指定文章/专栏)
AI 与同步相关配置见 .env.example:
- 生成 URL slug:配置
OPENAI_API_KEY - 生成封面图:配置
IMAGE_API_KEY
站点信息通过 .env 中的 SITE_* 环境变量覆盖。
- 没有
.env时,直接使用 nuxt.config.ts 里的内置默认值 .env.example只是示例,不会被自动加载;需要复制为.env才会生效
SITE_TITLE=染念的笔记
SITE_AUTHOR=染念
SITE_URL=https://dyedd.cn
SITE_EMAIL=1176996982@qq.com
SITE_PROFILE_AVATAR=/logo.jpg
SITE_PROFILE_INTRO=第一句|第二句
SITE_PROFILE_MOTTO=第一句|第二句
SITE_PROFILE_TECH_STACK=Python::https://img.shields.io/...|Vue::https://img.shields.io/...常用可配置项:
- 站点基础信息:
SITE_TITLE、SITE_AUTHOR、SITE_DESCRIPTION、SITE_KEYWORDS、SITE_URL、SITE_EMAIL、SITE_LANG、SITE_START_TIME - 个人资料:
SITE_PROFILE_AVATAR、SITE_PROFILE_BADGE、SITE_PROFILE_INTRO、SITE_PROFILE_MOTTO、SITE_PROFILE_STATEMENT、SITE_PROFILE_GITHUB_CHART、SITE_PROFILE_TECH_STACK - 社交与统计:
SITE_GITHUB_URL、SITE_QQ_URL、SITE_ANALYTICS_SCRIPT、SITE_ANALYTICS_WEBSITE_ID - 备案信息:
SITE_FOOTER_ICP_LABEL
其中一些值会自动复用,不需要重复配置:
profile.name复用SITE_AUTHOR- 邮箱链接自动由
SITE_EMAIL生成 - 页脚版权名复用
SITE_AUTHOR poweredBy固定为Powered by serenade和项目仓库地址- QQ 图标提示文案固定为
QQ - 友链申请联系文案固定为
邮箱 - 友链申请模板默认复用
SITE_AUTHOR、SITE_URL、SITE_DESCRIPTION、SITE_PROFILE_AVATAR SITE_PROFILE_INTRO、SITE_PROFILE_MOTTO用|分隔多行SITE_PROFILE_TECH_STACK用标签::图标URL|标签::图标URL配置
默认值直接定义在 nuxt.config.ts 中:
export const siteConfig = {
author: "染念",
title: "染念的笔记",
description: "Writing code, painful and happy",
keywords: "染念,染念的笔记,染念の笔记,染念的博客,博客,blog",
url: "https://dyedd.cn",
email: "1...2@qq.com",
lang: "zh-CN",
startTime: "2017-02-11",
};接口位于 server/api/,常用如下:
GET /api/posts?page=&pageSize=:文章列表(按日期倒序)GET /api/posts/<path>:单篇文章(meta + html + prev/next)GET /api/posts/search?keyword=&page=&pageSize=:全文搜索GET /api/columns/GET /api/columns/<path>:专栏与章节GET /api/tags/GET /api/tags/<tag>:标签统计 / 标签文章GET /api/projects/GET /api/projects/categories:项目GET /api/friends:友链 / RSS 朋友圈(需联网)
欢迎提交 Issue 和 Pull Request。
MIT