试用 EmDash:把现有 WordPress 博客复刻一版的完整记录
这篇文章记录的是一次试用:拿现有的 WordPress 博客当样本,在 EmDash 上复刻一版,把内容、外观和常用功能对过去,看看这套系统实际好不好用。
为什么要试
EmDash 是一套跑在 Astro 上的 CMS:前台是普通 Astro 页面,后台有完整管理界面,内容存在数据库里。只看文档不够,我想知道它能不能撑起一个已经在用的个人站——文章、项目、友链、留言、阅读数、邮件通知这些,原站都有。
所以目标很明确:
- 外观尽量贴近现站,方便对照;
- 文章、项目、菜单、社交资料尽量在后台改,方便体验后台;
- 把现有内容、媒体、评论和阅读数同步过去,否则试的是空站;
- 部署仍按常规 Linux + Nginx,和现在的主机习惯一致。
结论先行:作为一次完整体验,这条路走得通。但它不是“导入一下就能开箱”,而是主题重写、内容同步、自建部署叠在一起。值不值得换,这篇文章不下结论。
先定内容模型,再同步数据
现站按 WordPress 的习惯组织内容。对照到 EmDash 时,我先把类型拆开,再倒数据。
试用站里的集合大致是:
posts:普通文章,带分类、标签、摘要、正文、特色图;pages:关于页这类固定页;projects:项目,带状态、平台、技术栈、截图和视频;- 友链、留言走独立集合或插件接口。
分类和标签在 EmDash 里是 taxonomy。查询时名字必须和后台定义完全一致,比如 category 不能写成 categories,写错不会报错,只会 silently 查空。
还有两个很容易混的 ID:
- 前台 URL 用的是 slug,也就是
entry.id; - 评论、关联分类这些接口要的是数据库 ULID,也就是
entry.data.id。
混用的结果通常不是 500,而是“明明有数据,页面是空的”。这是试用时最先要对齐的心智模型。
内容怎么同步
文章、页面、项目、媒体,可以走 WordPress REST 或导出包导入。标题、正文、特色图、发布时间大多能对上,这一步比预想顺利。
花时间的是“数据在库里了,试用站前台却不对”的那些缝:
- 项目截图和视频已经在媒体库里,页面却还在热链原站地址。相对路径、本地媒体 URL 和绝对 URL 要当成同一种资源来解析,不能只认
https://。 - 分页、首页统计、项目数量,必须读导入后的集合,不能留演示数据。
- 菜单、社交链接、页脚状态、打字机文案,尽量做成后台可配,方便对照原站改。
评论头像也是一例。公开评论对象常常不带邮箱明文,只能拿哈希去国内头像源拉图;作者没有头像时,再退回站点 Logo。不处理的话,对照原站会突然觉得试用站很空。
阅读数:别信错字段
现站用 WP Statistics。导入时随手带过来一个很像阅读数的字段,其实是字数。文章几乎都是个位数或几百,跟印象里的浏览量对不上。
真正该用的是页面统计表里的 total,不是 words count。服务器上没有 WP-CLI 也没关系:写一个只允许登录管理员打开的导出页,浏览器里复制 JSON,再灌进试用站。
灌的时候还有一层合并问题。试用站自己也会计阅读,本地缓存里可能已经有一套数字。我的做法是:以现站统计为历史对照,再和试用站的累加值合并,避免两边互相覆盖。草稿、未发布内容要单独扫一遍,只导已发布条目会漏。
首页总阅读数也一样。只统计“今天活着的计数”会得到一个接近 0 的数;要把历史总和算进去,对照原站才有意义。
外观:对照现站,而不是另做一套
现站主题不是常见的“大封面 + 三列卡片”。页面有边框和准星,文章是三栏阅读布局:左边元信息,中间正文,右边目录和小组件。桌面宽度下我刻意保留了这三栏,方便并排看差异。
对照时守住这几条:
- 颜色只走一套品牌色,不另加第二强调色;
- 正文字体用干净的无衬线,标题靠字重和字号;
- 新区块仍然落在原来的页框和分隔线上。
还原过程中,几个“功能在,观感不对”的问题反复出现:
- 当前栏目不高亮。菜单项要标在
li上,CSS 才能吃到原来的选中态;伪元素的层级一错,高亮会画到导航后面。 - 灯箱有 DOM、有点击,但样式类名和原主题不是一套。绑定了文章图、项目图,却看不见遮罩。
- 关于页的 GitHub 贡献图,HTML 日历是按“星期 × 周”排的,SVG 却按另一套坐标画。格子对不上,悬停也就没有日期和提交次数。
这些都不算架构问题。试用的目的之一就是把这些细节对回去,否则评估的是一个不像自己站的演示页。
现站多出来的功能,用插件补
EmDash 的页面负责渲染。现站多出来的能力,试用时我做成站点插件:
- 访问量:按路径计数,和导入的历史值合并;
- 友链申请、通过、拒绝:给站长和申请人发信;
- SMTP:走现成的邮件插件;
- 技术栈、社交资料、页脚状态:做成插件设置,后台改完立刻生效。
邮件这一段踩过两个坑。
第一,SMTP 端口和加密必须配对。465 走 SSL,587 走 STARTTLS。端口和加密选反了,报错会是 TLS 版本不对,看起来像证书坏了,其实是自己选错了。
第二,插件自己创建的内容,有可能被设置成“保存后不再触发本插件钩子”。申请邮件如果只写在 afterSave 里,前台申请就发不出去。要通过、拒绝时,还得比较上一次和这一次的状态,只在变化时发信,避免改个标题也发出一封。
前台提示也要补。申请友链提交后对话框直接关掉、没有任何提示,会以为没提交成功。留言的成功/失败如果只插在文档流里,一滚动就看不见。这两处改成全局 toast 更合适。后台友链列表最好直接显示待审核、通过、拒绝,不必点进去才知道。
部署:在自己电脑构建
试用站的生产形态是 Astro 的 Node standalone:一个 Node 进程,前面 Nginx 反代。数据库用 SQLite,上传文件放本地目录。运行时是 Node 22。
这次最不该做的两件事:
- 把整个 Git 仓库连历史一起丢到服务器上;
- 在小内存 VPS 上直接
npm run build。
Vite 加上后台管理端,编译很吃内存,小机器会直接卡死。可行的顺序是:在本机构建,再打成更新包,服务器只装生产依赖、启动进程。
dist/ 也不是一个自包含可执行文件。服务器上仍然要 npm ci --omit=dev,因为运行时还要 CMS、SQLite、图片处理这些包。不要把 macOS 上的 node_modules 拷到 Linux,原生模块架构对不上。
更新包里不要带这些东西:
.git、node_modules、本机.env;- 日常更新不要覆盖试用站的数据库和上传目录;
- 密钥文件只在服务器上留一份,更新时跳过。
第一次可以带上已经导入好的数据库和媒体。之后改文章、菜单、SMTP、图片,只在试用站后台操作;改了页面、样式或插件代码,才需要本机构建、打包、覆盖、重启。
环境变量和域名
至少要准备这几项:
- 监听地址和端口。前面有 Nginx 时,进程只听本机回环地址;
- 对外站点 URL。构建和运行都要带上正式域名;
- 加密密钥。用来保护 SMTP 密码、第三方 Token 这类插件密文。用官方命令生成,不要随手
openssl rand。
有些面板的 Node 项目没有“环境变量”栏。变量写在项目根目录的 .env 里,启动脚本先读文件再拉起服务,即可。
站点 URL 会在构建时写进配置。只在服务器运行时改环境变量、不重新构建,邮件链接、canonical、Passkey、一部分绝对地址仍可能是旧值。如果试用域名有变,需要改变量、重新构建,再覆盖 dist 并重启。
多个域名反代到同一个进程可以。对外链接仍指向主域名,额外来源单独做成允许列表。
加密密钥丢了会怎样
文章、页面、图片还在。解不开的是库里已经加密的插件密码。换一把新密钥,再去后台把 SMTP、Token 重填一遍即可。轮换时可以把新旧钥匙写在一起,新的放最前面。
跑起来之后还会碰到的几件事
构建能过、进程能起来,不等于登录和生成的地址都正常。后面这几件是部署试用站时才暴露的。
魔法链接点了却登录失败
邮件能收到,点进去却提示登录失败。原因是会话目录在构建时写成了开发机上的绝对路径。Linux 上那个目录不存在,也不可写,校验接口直接 500。
处理:会话目录改成相对路径,并保证进程对会话目录、数据库、上传目录可写。面板里属主要用网站运行用户,不要只给 root。
Passkey 提示取消或超时
注册选项接口是成功的,浏览器却报取消。WebAuthn 的 rp.id 必须和地址栏主机名一致,而且要在 HTTPS 下操作。用 IP、内网域名或 HTTP 去加通行密钥,会失败得很难看。
Sitemap 里全是 localhost
后台已经改了站点 URL,环境变量也写了正式域名,sitemap.xml 里却还是本地开发地址。
Sitemap 优先读数据库里那条站点 URL。种子文件在第一次初始化时把它写成了本地地址。后台设置页展示的,往往是构建时的配置域名,看起来已经改对了,库里的值却没动。
后台“改域名”通常还要向新域名做一次校验。校验没成功就不会写库。就算写成功了,sitemap 本身也可能被缓存一个小时。
所以域名要同时对齐三处:构建变量、运行变量、数据库里的站点 URL。只改后台显示,生成出来的地址不会跟着变。
菜单顺序会自己变回去
后台调好的导航,重启或走一遍开发初始化后又回到种子里的顺序。原因是种子里带了菜单数据,初始化会重写菜单表。
菜单一旦交给后台维护,就不要再放进种子。开发环境的“一键填充演示数据”也要慎用,它可能把已经调过的库一并重置。
试用站怎么维护
日常可以分成两层:
反代记得把 Host、X-Forwarded-Host、X-Forwarded-Proto 传给 Node,并给上传留够请求体大小。SSL 仍由 Nginx 终止。
EmDash 给我的收获,主要是把一套自己正在用的站完整走了一遍:内容怎么建、主题怎么对、插件怎么补、小机器怎么部署。体验已经够了,换不换栈是另一件事,现在还没到那一步。
The post first appeared on crayonxiaoxin.