我的博客是纯静态的,想加评论区又不想养服务器。折腾一圈后选了 Twikoo,跑在 Cloudflare Worker + D1 上——访客填个昵称邮箱就能留言,不用注册,数据存自己的库,也没花一分钱。下面是我实际操作的步骤,以及几个卡了我半天的坑。


为什么选 Twikoo

静态站加评论,说白了就是借个后端存数据,页面上嵌个前端组件。我筛过一轮,最后留下 Twikoo 的原因很实际:

  • 访客不用注册。填昵称 + 邮箱就能评,不会劝退读者(Giscus 和 utterances 都要 GitHub 账号,对普通读者太重)
  • 和我的博客在同一张网。博客跑在 Cloudflare Pages,评论后端也在 Cloudflare,不会出现页面秒开但评论区一直转圈
  • 数据在手。评论存在自己的 D1 库里,想查想导都方便

其他方案各有各的问题:Waline 放 NAS 要绕 Cloudflare Tunnel,慢;Disqus 在大陆基本打不开。这篇不打算做选型对比,只讲怎么落地上线。

整体结构

博客页面(Cloudflare Pages)
        │  嵌一段前端脚本
        ▼
   Twikoo 前端组件
        │  发请求
        ▼
 Cloudflare Worker(Twikoo 后端)
        │
        ▼
   D1 数据库(存评论)

域名这块有个坑,得单独说。

先看一眼做完的效果。文章底部会出现评论区,访客填昵称邮箱就能留言:

评论区实际效果

第 1 步:部署后端

Twikoo 官方有现成的 Cloudflare 模板,拉下来就能用,全程大概二十分钟。

① 装 wrangler 并登录(Cloudflare 的命令行工具):

npm install -g wrangler
npx wrangler login   # 会弹浏览器让你授权

② 克隆官方模板 + 装依赖:

git clone https://github.com/twikoojs/twikoo-cloudflare.git
cd twikoo-cloudflare && npm install

③ 清掉 3 个不兼容的包。CF 免费版单个 Worker 代码上限 1MiB,这几个包在 Worker 里用不上(Node 兼容问题),清空能压到限制内:

echo "" > node_modules/jsdom/lib/api.js
echo "" > node_modules/tencentcloud-sdk-nodejs/tencentcloud/index.js
echo "" > node_modules/nodemailer/lib/nodemailer.js

第一次部署我忘了这步,bundle 超限直接失败。后面 D1 和 R2 的命令都依赖它,别漏。

④ 建数据库(存评论):

npx wrangler d1 create twikoo

输出里有个 database_id,填进 wrangler.toml 替换占位值。

⑤ 建表 + 建存储:

npx wrangler d1 execute twikoo --remote --file=./schema.sql
npx wrangler r2 bucket create twikoo   # R2 存评论里的图片,暂时不需要传图也可以跳过

建 R2 桶报 code 10042,是账号还没开通 R2,去后台点一下就行。

⑥ 部署:

npx wrangler deploy --minify

成功后会给你一个 https://twikoo-cloudflare.<你的用户名>.workers.dev。浏览器打开,看到 {"code":100,"message":"Twikoo 云函数运行正常..."} 就是后端活了。这个地址就是前端要用的 envId——但别急着用,先做第 2 步。

第 2 步:绑自定义域名(别跳过)

我被这个坑卡了最久,单独拎出来讲。

CF 给的 *.workers.dev 域名在大陆时通时不通。我的症状是:评论时有时无,头像一片空白,刷新几次又好了。一开始以为是头像配置错了,折腾半天才反应过来——评论数据根本没拉回来,那个域名不通。

解法是给 Worker 绑你自己的域名。wrangler.toml 加一行:

routes = [
  { pattern = "评论.你的域名.com", custom_domain = true }
]

再 npx wrangler deploy 一次,workers.dev 的路由会自动停用,之后前端 envId 就用你自己的域名。绑完之后再没出过加载问题。

第 3 步:接入前端

① 装 Twikoo 前端:

npm install twikoo

② 建 Comments.astro 组件(我博客用的 Astro,其他框架思路一样:放个容器 + 调 twikoo.init):

---
const path = Astro.url.pathname;
---
<section class="comments" id="comments">
  <h2>评论</h2>
  <div id="tcomment" data-path={path}></div>
</section>

<script>
  import twikoo from 'twikoo';
  const container = document.getElementById('tcomment');
  if (container) {
    const path = container.dataset.path || location.pathname;
    twikoo.init({
      envId: 'https://评论.你的域名.com', // 填第 2 步绑的域名
      el: '#tcomment',
      path, // 每篇传自己的 URL,评论就按篇分开了
    });
  }
</script>

View Transitions 的坑:博客如果开了 Astro 的站内切页动画,切到新文章时评论区不会自己刷新(第一篇能显示,点别的文章就空白)。要监听 astro:page-load,每次先把容器清空再重新 init,不然会重复渲染。没开的话不管它,init 一次就行。

③ 挂到文章页:在文章详情页 <Content/> 后面引入,放上 <Comments />。

④ 样式贴合主题:给 .comments 补点间距、用上站点的强调色。评论区底部那排 Markdown 提示图标和 “Powered by Twikoo” 页脚,我直接用 CSS 藏了,看着干净些。

第 4 步:管理评论

Twikoo 没有独立后台,管理入口就在评论窗口右下角那个小齿轮图标(不是点头像,我一开始也找错地方):

  • 第一次设密码:点小齿轮,会让你设管理员密码,设完存到后端
  • 日常管理:再点小齿轮输密码,能置顶、加精、删除、把评论标成博主

想藏得更深,可以用 HIDE_ADMIN_CRYPT 设个暗号:之后只有在昵称栏输入暗号的人,点齿轮才看得到管理入口。不过暗号只是藏界面,真正挡人的还是密码,两个别设成一样的。

踩过的坑

  1. 头像空白、评论时有时无:先查 workers.dev 通不通。大多是那个域名的问题,按第 2 步绑域名解决,别像我一样先去折腾头像配置。
  2. 同一篇文章的评论分成两处:CF 版不自动归一化 URL 尾斜杠,/post/1/ 和 /post/1 会被当成两篇。前端 path 统一格式就行,别直接裸用 location.pathname。
  3. 默认头像服务是坏的:Twikoo 默认的 weavatar.com 已经 500 了。换的时候注意 cravatar.cn 会无视 d= 参数,一直返回它家那个卡皮巴拉吉祥物,想要按邮箱生成几何图案得换尊重参数的镜像(我用的 sdn.geekzu.org)。管理面板里配 GRAVATAR_CDN 和 DEFAULT_GRAVATAR 两项。
  4. 邮箱格式要写全:QQ 邮箱只认 @qq.com,少个 .com 会被当普通邮箱,头像就查不对。
  5. 管理密码是双重 md5:前端先 md5 一次发给后端,后端再 md5 一次比对。要是直接改库重置密码,存 md5(md5(明文)),只存单层会一直提示密码错误。
  6. 配置改完要点保存:管理面板填的配置存数据库,每项改完得点保存按钮才落库。
  7. 前端锁版本:用 CDN 引 Twikoo 建议锁死版本号(比如 twikoo@1.7.22),国内访问可以走 npmmirror 或 zstatic 镜像,避免升级带出不兼容变更。

实际用下来

  • 评论功能该有的都有:发、读、回复、嵌套、Markdown、表情
  • 评论区内容自动做 XSS 过滤(CF 版用 xss 替代不兼容的 dompurify),不用自己配
  • 成本为零,CF 免费额度对个人博客的评论量来说绰绰有余
  • 唯一受限的是邮件通知:常规 SMTP 用不了(nodemailer 不兼容 Worker),要接 SendGrid 之类的 API。我没配,不影响使用

写在最后

这套东西真正省心的地方是后端几乎不用管——模板官方在维护,评论躺在我自己的库里随时能查。要说有什么非记不可的,就一条:一定绑自己的域名,别直接用 workers.dev。

你要是也在用静态框架搭博客、还没想好评论区怎么做,可以试试这个组合。这篇底下就是现成的评论区,能留言就说明它真的跑通了。

评论

评论加载中…