Artalk v2.10.0 变更日志与迁移指南
v2.10.0 是 v2.9.1 之后的下一个正式版本。本版本新增页面投票、SSO Token Exchange、MySQL Cloud SQL TLS 和无 CGO 的 SQLite 构建,并重构了 UI 客户端的生命周期、配置与类型系统。
升级前必读
v2.10.0 包含有意保留的接口与行为变更。服务端与 UI 客户端应同步升级;主题、插件、直接调用 HTTP API 或引用 Artalk TypeScript 类型的项目应先按本文完成迁移。
升级检查清单
- 备份数据库、配置文件和自定义前端资源。
- 二进制部署确认工作目录和所有相对文件路径;需要保持旧行为时显式传入
-w和绝对-c路径。 - 自行编译或打包服务端时升级到 Go 1.26.5。
- 如需修改应用时区,设置
timezone或ATK_TIMEZONE后完整重启 Artalk。 - 同时升级服务端与 UI 客户端,避免新旧 Vote API 混用。
- 检查本地与远程界面配置的优先级;默认改为本地配置优先。
- 搜索
useBackendConf、remoteConfModifier、两参数ctx.inject()、直接赋值ctx.conf/ctx.$root和artalk.update(...).xxx()。 - 重新编译使用 Artalk 类型或内部 UI 服务的主题与插件。
- Node.js 工具链使用现代版本;Artalk 仓库的开发基线为 Node.js 22.19 及以上。
主要更新
UI 与交互
- 新增页面投票,并可显示当前访客的已投票状态(#983、#998)。
- 新增
preferRemoteConf,明确本地与远程界面配置的合并优先级(#1000、#1011)。 - UI 改用依赖注入容器,并重新整理模块、生命周期和公开类型(#1006、#1007)。
- 新增 Artalk UI ESLint 插件,并升级到 v1.0.2(#995、#1010)。
- User-Agent 识别新增 OpenHarmony 和更多浏览器支持(#1087)。
- 评论链接的
rel属性新增ugc(#1120)。
服务端与 API
- 新增
POST /api/v2/sso/exchange,可将受信任 OIDC 身份提供方的访问令牌交换为 Artalk 会话令牌(#1134)。该功能默认关闭;生产环境应只配置受信任的 HTTPS Issuer,且/userinfo必须返回email_verified: true。 - Vote API 现在统一使用目标类型、目标 ID 和选择,并新增投票状态查询接口。
- 改进配置文件与数据目录查找,保留切换数据目录前的配置文件定位结果(#992)。
- MySQL 新增 Google Cloud SQL 双向 TLS 配置支持(#1104)。
构建与运行环境
- SQLite 改用纯 Go 驱动,正式构建不再依赖 CGO,也不再需要单独的
GORELEASER_CROSS工具链。跨平台产物可由标准 Go 工具链直接构建。 - Go 工具链升级到 v1.26.5,并更新相关依赖;登录会话的 JWT 实现升级到受维护的 v5 版本。已有 HS256 Token 的声明与签名格式保持兼容,升级服务端不会因此强制用户重新登录。
- 官方容器的构建与运行基础镜像升级到 Alpine 3.24;Go 构建版本仍固定为 v1.26.5,容器内的数据目录和配置路径保持不变。
- 更新前端与文档工具链,包括 Vite 8.1、Marked 18.0.7 和 KaTeX 0.17。
@artalk/plugin-katex的 peer 范围仍兼容 KaTeX 0.16.45 至 0.17.x,依赖升级不会强制现有主题同步更换 KaTeX。 - 新增插件注册表拉取脚本和 npm 已发布版本检查脚本。
- npm 包使用现代条件导出;不再兼容 Node.js 10 的旧模块解析行为。
文档与本地化
- 新增土耳其语(
tr-TR)和繁体中文配置模板。 - 新增日语 README。
- 重设计项目首页,补充多语言内容并优化响应式字号。
- 文档站集成 Git Changelog。
安全性与可靠性
- 后端 JWT 解析器升级到
github.com/golang-jwt/jwt/v5,显式限制为 HS256,继续校验过期时间,并新增旧 Token 格式、签名算法和过期行为的回归测试。 - Markdown HTML 清理器由无修复版本且存在 ReDoS 风险的
insane切换为持续维护的DOMPurify,保留原有标签、属性、class、style 和 URL scheme 白名单,并增加恶意标记与 ReDoS 回归测试。 - 前端锁文件将构建与开发工具链中的
fast-uri、brace-expansion、js-yaml、undici、Vite 等传递依赖固定到已修复版本;完整工作区依赖审计未发现已知漏洞。 - Google Cloud SQL TLS 会同时加载服务端 CA、客户端证书与私钥,校验服务器证书和主机名,并要求 TLS 1.2 及以上。三个证书路径必须一起配置,避免部分配置被静默忽略。
- Vote API 会拒绝非法、非正数、不存在或类型未知的投票目标。投票记录和目标计数在同一数据库事务中更新,任一步骤失败都会回滚。
- 插件 URL 由服务端过滤:相对 URL 与受信任 URL 可下发给客户端,不受信任的绝对 URL 会被移除。
- 插件注册表下载仅允许 HTTPS 和限定主机,并限制重定向次数、响应大小与请求时间。
- npm 版本检查不再通过 Shell 拼接包名,并会把网络或解析错误作为失败返回。
- 进程时区只在初始化时设置,避免并发请求修改全局时区状态。
突破性变更与迁移
1. 本地界面配置默认优先
v2.9.x 中远程配置会覆盖 Artalk.init() 传入的本地配置。v2.10.0 默认改为本地配置优先:
Artalk.init() 本地配置 > 环境变量 > 控制中心 = 配置文件默认无需新增配置:
Artalk.init({
server: 'https://comments.example.com',
site: 'My Site',
locale: 'zh-CN', // 保留本地值
})如需恢复“远程配置优先”,显式开启:
Artalk.init({
server: 'https://comments.example.com',
site: 'My Site',
preferRemoteConf: true,
})useBackendConf 已废弃并始终按 true 处理。设置为 false 不再阻止客户端读取后端必须提供的配置;它不能替代 preferRemoteConf。
2. 删除 remoteConfModifier
remoteConfModifier 不再属于公开配置。请根据用途迁移:
- 固定覆盖项直接放入
Artalk.init(),默认会优先于远程配置。 - 需要控制中心优先时使用
preferRemoteConf: true。 - 需要控制首次评论请求时使用
fetchCommentsOnInit。 - 仅需初始化后更新时,监听
created后调用update()。
const artalk = Artalk.init({
server: 'https://comments.example.com',
site: 'My Site',
fetchCommentsOnInit: false,
})
artalk.on('created', () => {
artalk.update({ locale: 'zh-CN' })
artalk.reload()
})不再提供可在插件初始化前任意修改远程配置的等价 Hook。
3. 配置类型区分完整值与输入值
Config 表示已经解析完成的完整配置,ConfigPartial 表示 Artalk.init()、update() 和插件配置更新所接受的递归可选输入。
import type { Config, ConfigPartial } from 'artalk'
function createComments(conf: ConfigPartial) {
return Artalk.init(conf)
}
function readResolvedConfig(conf: Config) {
console.log(conf.server, conf.pagination.pageSize)
}过去将 Partial<ArtalkConfig> 用作初始化参数的代码应改用 ConfigPartial。ArtalkConfig 仍可导入,但现在表示完整配置。
ConfigPartial 会保持函数、DOM 元素、Date、RegExp 和数组元素的原始语义,不会再把这些值错误地递归拆成对象字段。
4. DI 注册与解析分离
旧的双参数 ctx.inject(key, value) 注册方式已移除。使用 provide() 注册,使用 inject() 解析:
// v2.9.x
ctx.inject('example', createExample())
const example = ctx.get('example')
// v2.10.0
ctx.provide('example', () => createExample())
const example = ctx.inject('example')provide() 支持依赖列表与 singleton / transient 生命周期。自定义 TypeScript 服务键应通过声明合并扩展 Services。
5. ctx.conf 与 ctx.$root 不可替换
两者仍可读取,但不能整体赋值。运行时直接赋值会抛出带迁移提示的错误:
// 错误
ctx.conf = nextConf
ctx.$root = nextElement
// 正确
ctx.updateConf(nextConf)
const conf = ctx.getConf()
const root = ctx.getEl()如需更换根元素,请销毁旧实例并使用新的 el 创建实例。
6. Artalk.update() 返回 void
update() 不再返回 Artalk 实例。将链式调用拆开:
// v2.9.x
artalk.update({ pageKey: '/next' }).reload()
// v2.10.0
artalk.update({ pageKey: '/next' })
artalk.reload()7. 插件初始化与 created 时点
内置插件、本地插件和网络插件现在都会在本地与远程配置完成合并后初始化。网络插件不会再看到仅来自某一端的临时配置。
created 会在所有插件完成初始化后触发,随后触发 mounted。依赖旧时序的插件应把初始化前置逻辑放在插件函数内,把需要完整插件环境的逻辑放到 created 监听器中。
8. Vote HTTP API 与客户端方法
旧的投票端点:
POST /api/v2/votes/comment_up/123新端点:
GET /api/v2/votes/comment/123
POST /api/v2/votes/comment/123/uptarget_name 只能为 comment 或 page,choice 只能为 up 或 down。
生成的客户端方法同步调整:
await api.votes.getVote('comment', 123)
await api.votes.createVote('comment', 123, 'up', { name, email })旧端点和旧 votes.vote() 方法不保留兼容适配器。
9. SQLite 驱动改为纯 Go 实现
服务端 SQLite 驱动由基于 mattn/go-sqlite3 的 CGO 实现切换为 github.com/libtnb/sqlite 提供的纯 Go 实现。正式构建不再依赖本地 C 编译器、CGO_ENABLED=1 或 GORELEASER_CROSS_VERSION 对应的交叉编译工具链。
SQLite 磁盘文件格式没有改变,现有 db.file 数据库可以直接使用,普通部署无需修改数据库配置。升级前仍建议备份数据库;首次使用新版本启动时,Artalk 会照常执行数据库结构迁移。
自行编译或将 Artalk 作为 Go 模块嵌入的项目需要注意:
- 可以删除 SQLite 构建所需的 C 编译器、CGO 和 Goreleaser Cross 配置。
- 不要再依赖
mattn/go-sqlite3专属的构建标签、DSN 参数、C API 或动态扩展加载行为。 - 如有自定义 SQLite 编译选项、扩展或原生备份工具集成,应使用 v2.10.0 重新执行迁移、并发读写和备份恢复测试。
此变更不影响使用 MySQL、PostgreSQL、MSSQL 的部署。
10. 默认配置和数据目录采用 XDG 规则
未指定 --workdir / -w 时,Artalk 不再始终把启动目录作为工作目录。v2.10.0 的默认查找顺序如下:
- 配置文件:启动目录、启动目录下的
data、$XDG_CONFIG_HOME/artalk、/etc/artalk。 - 数据目录:如果启动目录存在
./data则保持旧工作目录;否则依次使用$XDG_DATA_HOME/artalk、/var/lib/artalk,均不存在时创建$XDG_DATA_HOME/artalk。
配置文件会在隐式切换数据目录前完成定位,但配置中的数据库、日志、上传目录等相对路径,以及 import、export、gen 等命令的相对文件参数,仍然基于最终工作目录解析。
现有目录中已经包含 ./data 的常规部署保持原行为。官方 Docker 镜像也显式指定了工作目录和配置文件,不受此变化影响。
如果二进制部署需要完全保持旧路径语义,请显式指定工作目录和配置文件:
artalk -w /srv/artalk -c /srv/artalk/artalk.yml server升级前应检查 db.file、log.filename、img_upload.path、IP 数据库和关键词文件等所有相对路径,避免在新的数据目录中意外创建空数据库或文件。
11. 源码构建要求 Go 1.26.5
go.mod 的最低 Go 版本从 1.22.7 提升到 1.26.5。该变化影响 go install、自行编译、发行版打包和将 Artalk 纳入 Go 构建流程的下游项目。
正式二进制和 Docker 镜像用户无需安装 Go。源码构建环境应升级到 Go 1.26.5;禁用 Go Toolchain 自动下载或处于离线环境的 CI 必须提前安装对应工具链。
12. 应用时区在进程初始化时固定
timezone 配置和 ATK_TIMEZONE 环境变量继续保留,用于设置独立于宿主系统或容器 TZ 的 Artalk 应用时区:
timezone: Asia/ShanghaiATK_TIMEZONE=Asia/Shanghai artalk server时区属于进程级全局状态,v2.10.0 只在 Artalk 进程初始化时设置一次,运行期间不支持动态切换。修改配置文件、环境变量或控制中心中的时区后,必须完整重启 Artalk 进程或容器;仅调用控制中心的“应用配置”不足以切换时区。
13. marked 18 与现代包入口
默认 Artalk 构建继续内置 Markdown 能力;ArtalkLite 不把 marked 打包进自身,需要下游提供兼容的 marked@^18.0.3。
Artalk 使用的 Marked、Renderer、parse()、setOptions()、use() 和 Tokenizer Extension 均不是 v18 专属 API,但 v14 到 v18 的上游解析细节仍可能影响自定义 Renderer、Tokenizer 或快照输出。使用这些扩展的项目应重新运行 Markdown 测试。
Node.js 10 和依赖旧式包解析的工具链不再受支持。Artalk 仓库开发与构建使用 Node.js 22.19 及以上。
保留的兼容入口
为了给主题和第三方插件留出迁移时间,以下入口在 v2.10.0 仍然存在,但已经标记为 deprecated:
| 旧入口 | 推荐入口 |
|---|---|
ContextApi | Context |
DataManagerApi | DataManager |
EditorApi | Editor |
ctx.data | ctx.getData() 或 ctx.inject('data') |
ctx.user | ctx.getUser() 或 ctx.inject('user') |
ctx.editor | ctx.inject('editor') |
ctx.list | ctx.inject('list') |
ctx.layerManager | ctx.inject('layers') |
ctx.checkerLauncher | ctx.inject('checkers') |
ctx.sidebarLayer | ctx.inject('sidebar') |
ctx.editorPlugs | ctx.inject('editorPlugs') |
editor.$el | editor.getEl() |
editor.getPlugs() | editor.getPlugins() |
editor.setReply() | editor.setReplyComment() |
这些别名仅用于过渡;新代码应直接使用推荐入口。完整公开类型请查看 TypeDoc。
其他变更
- 评论回复按钮改用组件实现。
- Sidebar 与 Auth UI 已适配新的客户端类型。
- 新增 npm 发布版本检查与插件注册表生成流程。
- 固定 Swagger TypeScript 客户端生成器版本并更新命令,避免不同开发环境通过
npx获取不兼容版本。 - 更新 GitHub Actions 运行时及制品、缓存、Docker、CodeQL 和 Codecov 相关 Actions;工作流输入与发布产物布局保持不变。
- 更新前端、Go 和文档依赖,并清理旧测试项目与 CI 配置。
完整提交差异可查看 v2.9.1...v2.10.0。
qwqcode