网站建设

biss.ren 网站建设:用AI搭建无头CMS

/3451 字 · 约 10 分钟
目录 · 5 节

中秋回家,时间确实太漫长了,不出去在家里也不知道干什么,就用AI来搭建之前一直没有做的无头WordPress。早在2023年的时候,我就尝试过无头 WordPress,但是试了一下确实觉得很牛逼,但是没有这个动力去做。最近AI时代来的太快了,我本来想的是完全再重新做一套全新的CMS,包括前端和后端管理系统,但还依旧保留原有的wordpress和push-markdown推送文章的机制,尝试了一天,还是太费劲了,最后还是放弃了。这俩天还是回到采用Headless的方案,也就是数据库和后台管理系统依旧使用原有的wordpress,就前端重写一套新的UI。好在有AI,公司的这个月的kiro额度还没用完,于是大部分都用opus5来做。虽然听起来工作量很大,但其实做的不是很复杂,花了一天多,全都是AI跑出来的,我都没有敲过一行代码。

这次biss.ren整体采用暗黑的样式,一些颜色的点缀依旧使用粉色。我发现我真挺喜欢粉色的,不知道是不是bilibili的影响。这次移动端的适配做得更加全面,或者说首页的排版其实是以移动端为主的。原来的argon主题三四年没维护了,对移动端的适配实在是不尽人意。下面就是biss.ren 1.0版本,整体看下来还是比较满意的,后面有bug再让AI修一下。

biss.ren 首页 PC 端与移动端效果对比

下面都是用AI写出来的内容,仅供参考。

整体架构

技术栈是 Next.js 16(App Router)+ React 19 + Tailwind CSS v4 + WordPress / WPGraphQL,运行在自建服务器上,而不是部署到 Vercel。读内容走 GraphQL;访客发表评论则先交给新站自己的接口,再由服务端调用 WordPress 的 GraphQL mutation。

访客浏览器
    │ HTTPS
    ▼
biss.ren 的 nginx(证书、域名跳转、反向代理)
    │ 127.0.0.1:3100
    ▼
Next.js(页面渲染 / ISR / 图片优化 / 评论接口)
    │ GraphQL、媒体文件;同机部署时走 127.0.0.1:8080
    ▼
WordPress 的内网 nginx ── PHP-FPM ── WordPress 内容与数据库

另一边:szx.life 仍然通过原有站点对外提供 WordPress 页面和原图

NEXT_PUBLIC_WORDPRESS_API_URL 是 WordPress 的公网地址;服务端可以另外设置 WORDPRESS_INTERNAL_URL。两套应用同机部署时,Next 查 /graphql 和回源取图片走内网,不必绕到公网/CDN 再回来。没配内网地址时,则退回公网地址,方便本地开发。

取数封装在 fetchGraphQL 中:向 WordPress 的 /graphql 发 POST,并给请求附上缓存标签。开发和构建阶段用 GraphQL Code Generator 从真实 schema 生成类型;由于源站关闭了公开内省,生成 schema 时需要 WordPress 应用密码认证。密码留在本地环境变量里,不能提交到仓库,也不需要暴露给浏览器。

页面怎么生成和更新

路由大致分三类:

  • / 是文章索引。WPGraphQL 一页最多取 100 条,首页用 contentNodes 的游标翻页拿全文章,按年份倒序分段;每条展示标题、日期、分类和小缩略图。首页的 ISR 周期是 600 秒。
  • /shuoshuo/ 展示说说时间线,也用 600 秒的 ISR;单条说说和普通文章一样可以进入内容页。
  • /[...slug]/ 处理文章、独立页面和单条说说。构建时通过 generateStaticParams 预生成已有内容路径,未预生成到的路径也可按需生成;内容页的 ISR 周期是 3600 秒。

这不是「每次访客请求都去 WordPress 查一遍」,也不是「每次发文必须把整个网站重新构建一遍」。页面可以先由构建或访问生成,再由 ISR 按间隔更新。想让刚发的内容尽快出现,还可以调用需要 X-Headless-Secret-Key 的 /api/revalidate/,按路径或 wordpress 等缓存标签触发重新校验;密钥只放服务端环境里。

中文路径这里踩过一个坑:Next 收到的 slug 可能是大写百分号编码,但源站的 contentNode(idType: URI) 对这类编码不一定能找到文章。页面在查询前会逐段解码,构建期生成路径时也做相应处理。另一个优化是用 React 的 cache() 复用同一次请求中「生成 metadata」和「渲染页面」都需要的内容节点查询,避免重复打到 WordPress。

图片和正文不是把 HTML 原样贴上去就完事

文章正文来自 WordPress 的 HTML,原主题曾给图片写入 zoom 等内联样式,也有把真实图片地址放在 data-original 的懒加载写法;离开原主题的 JavaScript,直接渲染可能出现尺寸乱跳或只显示占位图。

现在服务端用 HTML 解析器加工正文:恢复真实图片地址、去掉会干扰排版的内联缩放、补充 srcset / sizes / 懒加载,并给标题补齐目录锚点。正文图片提供 384、640、828、1200 等宽度档,由 Next 图片优化器按设备选择;点击图片则可以通过灯箱查看,关闭脚本时还保留打开原图链接的兜底。首页的小封面优先取 WordPress 自己生成的 thumbnail,文章头图优先取较大的变体,不让几十像素的小图先回源下载整张原图。

这里还有个回源细节:给图片优化器的 WordPress 媒体地址会转成本站的 /wp-media/... 相对路径,再由 Next rewrite 指向 WordPress 的 /wp-content/...。同机部署时,优化器便能走内网取图;访客点击「查看原图」仍使用公网地址,因为浏览器访问不到服务器的 127.0.0.1。

页面样式以 Tailwind v4 为主,WordPress 灌进来的正文则由 .prose 规则统一排版。整体只做一套暗色主题,中文字体用 MiSans,颜色和排版尽量由新站控制,不再依赖老站的 Argon 主题。

评论如何接回 WordPress

文章和单条说说可以读取 WordPress 评论。前端把评论按父子关系组织成回复树;评论 HTML 在展示前做白名单清洗。发表时,浏览器提交表单到 biss.ren/api/comments/,Next 校验内容长度、邮箱和回跳地址,再调用 WPGraphQL 的 createComment。成功后只让对应内容的缓存标签和页面过期,不用为了一个回复清掉整站缓存。

这个写接口还有蜜罐字段和按 IP 的内存限速;WordPress 自身的重复评论、发送频率等规则也会继续生效。不过内存限速只适合目前这种单进程部署,重启会清空,多实例也不会共享;它不是完整的反垃圾方案。现有 WordPress 配置允许匿名评论,评论策略和审核仍需要在后台自己留意。

部署和搜索引擎这两件小事

对外访问先到 nginx:HTTP 和 www.biss.ren 收敛到 https://biss.ren,HTTPS 再反代到只监听 127.0.0.1:3100 的 Next 进程。systemd 管理进程、重启和日志;WordPress 另有只监听回环地址的内网 nginx 入口。发布新代码后需要在服务器构建并重启服务;这些配置都放在项目的 deploy/ 目录里,而不是手工配完就忘。

因为两个域名展示的是同一份文章,新站默认不允许搜索引擎收录:除页面的 robots metadata 外,响应头也会加 X-Robots-Tag: noindex, nofollow。robots.txt 仍允许爬虫抓页面,否则它反而读不到 noindex。等确定老站、新站哪一个作为主要入口,再显式打开 NEXT_PUBLIC_ALLOW_INDEXING=true;新站自己的 canonical、Open Graph 和 sitemap 都以 biss.ren 为基准。这只是代码中的默认策略,实际对外状态还取决于服务器的域名、证书和环境变量配置。

评论

还没有评论,来说第一句。

发表评论

邮箱只用来显示头像,不会公开