添加 Waline 评论

2026-05-23T00:00:00-05:00 | 3分钟阅读

@

起因

我一直想在文章地步加个评论框:

  1. 网站自带评论框 —— 留言不要求登录,流程越简单越好
  2. 长毛象评论也显示 —— 我转发的那条 toot 下面的回复,自动同步到对应文章页面

方案

Claude 给了 5 种主流方案的对比:

方案用户门槛部署复杂度dream 主题原生支持
Utterances需 GitHub 账号⭐ 5 分钟
Disqus任意社交账号 + 广告⭐ 10 分钟
Waline邮箱即可,可匿名⭐⭐⭐ 30-60 分钟
Twikoo邮箱即可,可匿名⭐⭐ 20-30 分钟
长毛象评论需长毛象账号⭐⭐⭐ 自己写

Waline 是中文工具里最成熟的"可匿名 + 自托管"方案,dream 主题内置支持,于是我选择了Waline。

后端选型

Waline 需要一个后端服务(Node API + 数据库)。问 Claude 部署位置时我选择统一在 Cloudflare 生态。

我自己搜了一下找到 Cloudflare 可以使用的第三方 port wuyilingwei/Waline_On_Worker (作者明确声明是"AI 辅助开发,生产前自行评估风险"):

一个运行在 Cloudflare Workers 上的 Waline 评论系统后端实现,使用 D1 (SQLite) 作为数据存储。实现了 Waline 的绝大多数功能。

部署 Waline 后端

整个流程(用了 ~20 分钟):

# 1. 装 pnpm(之前没用过)
brew install pnpm

# 2. 克隆 repo 到统一的 GitHub 文件夹
cd ~/Documents/GitHub/
git clone https://github.com/wuyilingwei/Waline_On_Worker.git
cd Waline_On_Worker

# 3. 装依赖
pnpm install
# 报错:[ERR_PNPM_IGNORED_BUILDS] esbuild、sharp、workerd 需要构建脚本批准
pnpm approve-builds   # 交互式批准这三个 native 包

# 4. 创建 D1 数据库
npx wrangler d1 create waline-db
# 输出 database_id = ""
  1. Repo 里没有 wrangler.toml 模板。需要手动建一个:
name = "waline-comment"
main = "src/index.ts"
compatibility_date = "2024-12-01"

[[d1_databases]]
binding = "DB"
database_name = "waline-db"
database_id = "database_id"

[vars]
SITE_NAME = "sitename"
SITE_URL = "https://mysite.com"
SECURE_DOMAINS = "https://mysite.com"

继续:

# 6. 初始化 D1 数据库 schema
pnpm run db:init
# ⚠️ 这条命令默认跑在本地开发数据库!schema 没到线上!

# 7. 生成 JWT 密钥
openssl rand -hex 32
# 复制输出
npx wrangler secret put JWT_SECRET
# 粘贴

# 8. 部署 Worker
pnpm run deploy
# 输出:https://waline-comment.yoursite.workers.dev

# 9. 浏览器打开 /ui/register 注册第一个用户(自动成为 admin)

500 Internal Server Error

在 /ui/register 注册时 500 报错。因为第 6 步的 pnpm run db:initpackage.json 里是 wrangler d1 execute waline-db --file=./schema.sql —— 没有 --remote,新版 wrangler 默认跑在本地开发库,线上库没初始化。

修复:

npx wrangler d1 execute waline-db --remote --file=./schema.sql

Hugo 集成

后端搭建完毕后,前端要把评论框接上:

# hugo.toml
[params]
waline = true
walineServer = "https://waline-comment.leonashao.workers.dev"

dream 主题内置支持 waline = true,但默认 init 配置不太好看,所以覆盖了 layouts/partials/waline.html

<div id="waline" class="waline-wrapper"></div>
<script type="module">
  import { init } from 'https://unpkg.com/@waline/client@v3/dist/waline.js';
  init({
    el: '#waline',
    serverURL: "https://waline-comment.leonashao.workers.dev",
    dark: 'html.dark',
    lang: 'zh-CN',
    requiredMeta: [],             // 都不强制;昵称留空即匿名
    pageview: false,              // 浏览量交给 GA
    reaction: false,              // 关掉评论赞踩
    meta: ['nick', 'mail'],       // 只显示昵称 + 邮箱,去掉网址
    locale: {
      nick: '昵称(必填)',
      mail: '邮箱(可选)',
      placeholder: '欢迎留言(◍•ᴗ•◍)',
      sofa: '快来抢沙发!',
    },
  });
</script>

长毛象评论

主要是 Mastodon API 的客户端实现。layouts/partials/mastodon-comments.html 是一个独立 partial,frontmatter 里有 mastodon 字段才渲染:

{{ with .Params.mastodon }}
<section class="mastodon-comments" data-instance="m.cmx.im" data-status-id="{{ . }}">
  <h3>长毛象上的讨论</h3>
  <div class="mastodon-comments-list">加载中...</div>
</section>
<script>
  fetch('https://m.cmx.im/api/v1/statuses/' + statusId + '/context')
    .then(r => r.json())
    .then(data => {
      // 渲染 data.descendants 里的 replies
    });
</script>
{{ end }}

完整代码 ~100 行 JS,处理:直接回复 toot 的过滤(不显示回复的回复,避免嵌套)、HTML 转义、头像渲染、时间格式化、错误处理。

用法:每次想要某篇文章带长毛象评论,就:

  1. 在长毛象上发一条 toot 提到这篇文章
  2. 复制 toot 的 ID(URL 最后一段)
  3. 加到 frontmatter:mastodon: "111234567890123456"
  4. push,~2 分钟后该文章页底部就会出现"长毛象上的讨论"板块

没加这个字段的文章页面就不显示,纯 Waline。

© 2025 - 2026 Leona的田园牧歌

🌱 Powered by Hugo with theme Dream.

关于我

Leona

  • 女的。
  • INFJ -> ENFJ 年纪大了变成E人了。
  • 长毛象链接点这里!
  • 做了九年数据科学家,但是每次管自己叫”科学家“,都很羞愧。职业+J人,习惯把日常生活数据化。
  • 玩了十几年相机,三十岁以前拍人像擅长无痕修图,三十岁以后拍动物植物大自然。
  • 厌倦城市,旅行目标大多是看动物。
  • 嘴太叼,不好吃宁愿饿着,还好手艺不错,不会饿死自己。
  • 没体能天赋,从小长跑最后一名,但是热爱运动,练过跑步、举铁、泰拳、网球、crossfit,现在重心转向功能性训练。
  • 现阶段人生目标是找个山头归隐,自给自足,田园牧歌,种菜养花,遛猫逗狗,养鸡喂牛。