我的博客是纯静态的,想加评论区又不想养服务器。折腾一圈后选了 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设个暗号:之后只有在昵称栏输入暗号的人,点齿轮才看得到管理入口。不过暗号只是藏界面,真正挡人的还是密码,两个别设成一样的。
踩过的坑
- 头像空白、评论时有时无:先查 workers.dev 通不通。大多是那个域名的问题,按第 2 步绑域名解决,别像我一样先去折腾头像配置。
- 同一篇文章的评论分成两处:CF 版不自动归一化 URL 尾斜杠,
/post/1/和/post/1会被当成两篇。前端path统一格式就行,别直接裸用location.pathname。 - 默认头像服务是坏的:Twikoo 默认的 weavatar.com 已经 500 了。换的时候注意 cravatar.cn 会无视
d=参数,一直返回它家那个卡皮巴拉吉祥物,想要按邮箱生成几何图案得换尊重参数的镜像(我用的 sdn.geekzu.org)。管理面板里配GRAVATAR_CDN和DEFAULT_GRAVATAR两项。 - 邮箱格式要写全:QQ 邮箱只认
@qq.com,少个.com会被当普通邮箱,头像就查不对。 - 管理密码是双重 md5:前端先 md5 一次发给后端,后端再 md5 一次比对。要是直接改库重置密码,存
md5(md5(明文)),只存单层会一直提示密码错误。 - 配置改完要点保存:管理面板填的配置存数据库,每项改完得点保存按钮才落库。
- 前端锁版本:用 CDN 引 Twikoo 建议锁死版本号(比如
twikoo@1.7.22),国内访问可以走 npmmirror 或 zstatic 镜像,避免升级带出不兼容变更。
实际用下来
- 评论功能该有的都有:发、读、回复、嵌套、Markdown、表情
- 评论区内容自动做 XSS 过滤(CF 版用 xss 替代不兼容的 dompurify),不用自己配
- 成本为零,CF 免费额度对个人博客的评论量来说绰绰有余
- 唯一受限的是邮件通知:常规 SMTP 用不了(nodemailer 不兼容 Worker),要接 SendGrid 之类的 API。我没配,不影响使用
写在最后
这套东西真正省心的地方是后端几乎不用管——模板官方在维护,评论躺在我自己的库里随时能查。要说有什么非记不可的,就一条:一定绑自己的域名,别直接用 workers.dev。
你要是也在用静态框架搭博客、还没想好评论区怎么做,可以试试这个组合。这篇底下就是现成的评论区,能留言就说明它真的跑通了。
评论