从静态页面迁到 Next.js,后来网站也变了
迁移起点是复用导航和文章模板,随着留言、后台和上传加入,部署也从纯静态站走向 Node.js 服务。
这个网站最早可以理解成一组静态页面。内容少的时候,复制一份页面再改标题并不麻烦;页面多起来以后,导航、页脚和卡片样式各有几个版本,改一次就要到处找。
迁移到 Next.js 的最初目的其实很朴素:把重复部分拆成组件,让文章和页面共享同一套结构。后来留言、评论、后台、媒体上传和备份陆续加入,网站也不再适合被描述成“纯静态博客”。
路由迁移比复制页面更重要
文章详情现在使用 App Router 的动态路由 /posts/[slug]。仓库里的 MDX 负责正文,解析层读取 frontmatter,页面再生成标题、描述、目录和结构化数据。
这种拆分以后,文章文件只关心内容,页面组件处理显示。分类、标签、搜索索引、RSS 和站点地图也能复用同一份公开文章数据,不必分别维护列表。
content/posts/*.mdx
↓
文章解析与过滤
↓
详情页 / 搜索 / RSS / sitemap这里最关键的是“过滤”也要共用。草稿或私密文章如果只在列表页隐藏,却仍被详情接口或搜索索引读取,就不算真正私密。
服务端和客户端各做合适的事
迁移过程中,我一度倾向于把组件都写成客户端组件,因为状态和点击事件更直接。代价是浏览器要下载更多 JavaScript,首屏还可能先出现占位,再等客户端拿数据。
现在更合适的边界是:文章读取、搜索索引和页面元数据尽量放在服务端;主题切换、播放器、表单和即时筛选留在客户端。不是所有页面都必须静态生成,也不是用了 Next.js 就应该把所有事情交给服务端。
部署方式也随功能改变
早期页面可以静态导出到 Cloudflare Pages,但当前仓库包含 Node.js API、管理员登录、R2 上传和本地持久化目录。生产部署因此需要一个持续运行的 Next.js 服务,仓库提供了 Docker Compose,并由 Nginx 在外层转发请求。
Cloudflare 仍可以提供 DNS、代理或对象存储,但这和“网站部署在 Cloudflare Pages”是两回事。写技术记录时把这几个概念混在一起,之后看的人会很难判断环境变量到底在构建时还是运行时生效。
一些功能已经不再是计划
MDX、目录、代码高亮、RSS、搜索都已经出现在当前项目中,所以它们不应该继续留在“以后再做”的清单里。现在更需要花时间的是公开内容权限、加载性能、真实数据的降级方式,以及把后台配置真正用起来。
这次迁移没有停在某个提交上。静态页面解决了“先有一个网站”,Next.js 组件化解决了“继续维护”,Node.js 服务又承接了动态功能。技术选型不是一次宣言,而是随着网站实际需要不断调整边界。