深夜台灯下的 Nook:我如何用 Nuxt 3 给自己造了一座「数字书房」
本文介绍最近刚完成的个人小项目 Nook——一套个人站点 + 自建 CMS 的全栈方案:前台 SEO、后台在线发文、Node API 与 MongoDB 统一数据源。
线上示例:www.zhouyi.run(2g2h的小服务器部署多个项目快跑满了 有点慢嘻嘻)
一、缘起:不想再把文章交给别人的首页算法
故事要从一个很普通的晚上说起。
那天我在某平台写完一篇技术笔记,刷新首页,发现推荐流里全是无关内容;想搜自己半年前写的东西,关键词换了三四个才勉强翻到。我突然有点较真:如果「我」这个字连自己的文字都留不住,那写博客到底是在存档,还是在给别人的产品填时长?
当然,我完全理解平台的价值——流量、互动、话题圈。只是对我来说,还想要另一件东西:一块完全属于自己的地方。像书房:书架怎么摆、灯开多亮、墙上挂什么画,都由自己决定。于是有了 Nook 这个名字——角落、小窝、可以躲进去翻书写东西的地方。
它不是「又一个博客模板 demo」,而是从真实需求长出来的:前台要给访客和搜索引擎看完整 HTML,后台要能在线改文章、改作品、改站点配置,数据不能只活在浏览器里。这就是后来三仓结构的雏形。
最重要的是个人主页就是要酷酷的,能多炫就做多炫!!!
二、整体架构:三条轨道,一列火车
如果把 Nook 想成一列火车:
- 车头(WEB) 是 Nuxt 3 前台:负责门面、SEO、动效与阅读体验。
- 乘务室(ADMIN) 是 Vue 3 + Vite 管理端:你一个人上车操作,乘客看不见也没必要看见。
- 铁轨与动力(SERVER) 是 Express + MongoDB + Redis:所有正儿八经的数据读写都在这里落地。
访客 / 爬虫
→ Nuxt 3(SSR、meta、sitemap)
→ Nitro /api 代理或服务端直连
→ Express 公开 API(/v1/public/nook …)
→ MongoDB(文章、作品、站点配置…)
→ Redis(Session、缓存等)
你本人
→ Vue 管理后台 SPA
→ Express 管理向 API
→ 同上 MongoDB
这样设计有一个很实在的好处:内容只有一份真相来源。后台保存进数据库,前台下次请求就是新内容;不用纠结「静态站构建完才发现后台又改了一稿」——当然,若你以后做 ISR/SSG 再生成,也只是在这条链路上加一层策略,而不是换一套数据源。
三、技术栈:不堆名词,只选「能扛事」的队友
前台(Nook WEB)
| 方向 | 选型 | 一句话 |
|---|---|---|
| 框架 | Nuxt 3、Vue 3、TypeScript | 服务端取数、useHead、文件路由,SEO 友好 |
| 样式与组件 | Tailwind、shadcn-nuxt、Radix Vue | 组件可访问性 + 自己可控的设计 tokens |
| 图标 | @nuxt/icon(Iconify) | 按需、少打包体积 |
| 动效 | motion-v(官方 Nuxt 模块)、Lenis、vue-use-spring 等 | 动画跟 Vue 生命周期走,滚动手感单独调教 |
| 代码高亮 | Prism(文章渲染管线中) | 技术文阅读体验 |
管理后台(ADMIN)
Vue 3、Vite、Element Plus、Pinia、Vue Router、wangEditor、ECharts、Socket.io 客户端——典型中后台全家桶,目标只有一个:快、稳、少折腾,把精力留给写文章而不是给后台写后台。
服务端(SERVER)
Express、Mongoose、Redis、JWT、BullMQ、Socket.io、限流、上传……这里不展开每一行配置,但记住一条:验证码、JWT、敏感入库尽量留在 Node,Nuxt 侧可做代理,别把密钥摊在浏览器里。
四、动效与氛围:书房可以安静,也可以有星光
我承认:纯文本的「个人站」也能用,但我想要一点仪式感——不是炫技到卡顿,而是打开首页时心里会「哦,回家了」。
- 首页:星空感的背景、流体光标(Canvas/WebGL 一类交互)、滚动时的文字揭示与视差区块,配合 Lenis 平滑滚动,路由切换后还会在
page:finish等钩子里resize,避免高度变化后滚动「发涩」。 - 内页:部分路由下会有低调的交互网格背景,
pointer-events-none不挡点击——好看不能耽误办事。 - 文章页:暗色阅读、封面与作者信息、右侧目录 + IntersectionObserver 高亮当前章节、上一篇/下一篇、文末留言——长文读完不用拼命找「返回」。
五、SEO:让搜索引擎也找得到这间书房
个人站最怕的是「写得认真,爬虫看不见」。Nook 在前台侧做了几件踏实事:
- 全站 head:从接口拉站点配置,动态拼接 title、description、keywords、Open Graph、canonical。
- 文章页单独
useHead:与全站默认 meta 解耦,避免详情页被错误描述糊脸。 - JSON-LD:
BlogPosting结构化数据(发布时间、修改时间、作者、封面等),方便搜索与社交预览。 /robots.txt+/sitemap.xml:sitemap 合并固定页面与全部文章 URL,并带lastmod,robots 里声明 Sitemap 地址。
这些都不是「玄学 SEO」,而是可验证、可迭代的工程项;
六、踩坑与工程细节:真实项目总有补丁
在 Nuxt + Tailwind 的某些组合下,PostCSS 若错误加载了含 import.meta 的生成文件,会报 Cannot use 'import.meta' outside a module。Nook 在 nuxt.config 里用 hook 把 Tailwind 配置拉回到可预测的 CJS/对象形态,并显式指定 content 扫描路径——这种补丁不性感,但能省下半夜查 issue 的时间。
七、部署与边界
- 支持 Docker 构建前台镜像的示例命令
- 多环境时用
NUXT_CMS_API_BASE指向上游公开 API,本地、预发、生产各写各的
八、结语:Nook 不是终点
回到那个较真的晚上:我想要的其实不是「逃离平台」,而是多一个完全可控的存档与表达空间。Nook 还在长——可能加更多内容块类型、可能把部分页面 SSG、可能给动效加 prefers-reduced-motion 降级——但内核已经清楚:数据在我手里,HTML 给爬虫看,书房门牌写我自己的域名。
如果你也在造自己的站,希望这篇手记能给你一点架构上的参照,或至少一点「我也能慢慢搭起来」的信心。
项目结构速览
Nook/
├── WEB/ # Nuxt 3 前台
├── ADMIN/ # Vue 3 管理后台
└── SERVER/ # Express API