Flarum 2.0.0-rc.1 发布 🎉
我们做到了。历经近三年的开发、八个测试版、397 个合并的拉取请求以及 30 位贡献者之后——Flarum 2.0 现已推出首个发布候选版本(Release Candidate 1)。
✅ 可供早期采用者在生产环境中安全使用。从此版本到稳定版的升级路径已完全支持——从 rc.1 到最终 2.0.0 的升级将十分顺畅。请采取常规预防措施:备份数据库,先在本地或预发布环境中测试(若有),并制定回滚计划。
👀 你已经在运行它了。就在这个论坛 —— discuss.flarum.org —— 也已更新至 rc.1。
🧪 想抢先体验 Flarum 2.0? 欢迎查看我们的每日构建演示站点:nightly.flarum.site,该站点每天根据最新的 2.x 代码重建。
🧭 “发布候选版本” 究竟意味着什么?
RC 版本是我们认为已经准备好正式发布的版本。它功能完整,API 已冻结,如果没有发现关键问题,rc.1 将直接成为 2.0.0 正式版,且不会再有功能性变更。
具体来说:
- 不再有破坏性变更。扩展 API 已锁定。一个针对 rc.1 构建、兼容 2.x 的扩展,在 2.0.0 正式版上依然可以工作。
- 从此拥有干净的升级路径。如果你正在使用 rc.1,升级到 2.0.0 只需执行一条
composer update 命令——绝无意外。
- 我们将快速处理回归问题。任何在 rc.1 中报告的、影响实际使用的回归问题,都将被列为最高优先级处理。
现在,轮到你了——我们需要有人在真实论坛上运行此版本。我们看到的安装场景越多,2.0.0 正式版发布时的意外就越少。
- 安装它。在本地,或者在你的预发布环境中——最好能基于一份真实数据的副本。
- 像日常使用论坛一样使用它。发帖、回复、管理、上传、搜索、个性化。尝试你依赖的扩展。
- 告诉我们使用体验——好的坏的都行。Bug、升级过程中的卡顿、无法工作的扩展、用户界面上的小瑕疵、奇怪的性能下降。另外,“它就这么直接能用了” 对我们来说也很有参考价值。
反馈渠道:
不确定问题属于哪一类?在论坛上发帖讨论即可,我们会帮你归类。
✨ rc.1 中有哪些新变化?
rc.1 是一个侧重于完善与强化的版本。除了测试版周期中收到的一些小功能请求外,重点放在了性能、安全性和整体打磨上。以下变化自 beta.8 发布后添加。
🔒 安全性强化
rc.1 中整合了一系列针对密码流程和会话管理的修复。
- 密码重置令牌现在会在提交时检查是否过期。此前仅在渲染重置表单时验证过期时间窗口——一个已过期的令牌如果被直接提交,仍有可能完成密码重置。
- 更改密码后,现在会使所有现有会话失效。当密码更改时,用户的所有会话、”记住我“令牌和开发者令牌都会被清除。
- 请求新的密码重置会删除旧的令牌。任何时候,一个用户只能存在一个有效的密码重置令牌。
- 强化了通过 URL 获取头像的过程。用于获取远程头像的 Guzzle HTTP 客户端现在禁用了重定向,强制执行短超时,并在将响应缓冲到内存前拒绝过大的响应。
- 现在会验证 Logo、Favicon 和深色模式 Logo 的上传。之前只有头像会通过图片验证器——rc.1 引入了一个共享的
AbstractImageValidator,并将其接入到所有图片上传的控制器中,弥补了之前管理后台图片端点接受非图片上传的漏洞。
⚡ 性能提升
- 消除了讨论列表中的 N+1 查询问题。讨论列表中的一系列 N+1 查询模式(如标签权限子查询、点赞/用户组预加载、擦除请求和消息计数的可见性守卫)已被解决——与
beta.8 相比,论坛首页现在大约只发出四分之一数量的查询。
- 为
notifications 表添加了新的复合索引。在大型论坛上,未读计数查询变得明显缓慢。新的 (user_id, is_deleted, read_at, type) 复合索引解决了此问题。
- 标签别名(slug)现在通过一次查询解析。
TagFilter 之前为每个别名执行一次查询;rc.1 将它们批量处理为一个 whereIn 查询。
- 前端性能优化。在文档头部添加了预连接 / DNS 预取提示;为 Logo 应用了
fetchpriority 属性和预加载提示;以及一个基于 sessionStorage 的 CSS 加载器,消除了冷加载时可能出现的无样式内容闪烁。视口(viewport)元标记也已放宽,移动端不再禁止捏合缩放。
➕ 小功能添加
- 扩展管理页上的重置设置按钮。每个捆绑扩展的管理页面现在都有一个 “重置为默认值” 按钮,由新的
DELETE /api/settings 端点和 Settings\Event\Reset 事件支持,扩展可以监听该事件以执行自己的清理工作。
- HiDPI 头像。上传的头像现在会自动生成
@2x 和 @3x 变体,并且 <Avatar> 组件会渲染 srcset 属性,使头像在高清视网膜屏和移动设备上显示得更清晰。
- 废弃扩展列表每周自动同步。面向管理员的废弃扩展包警告系统现在会每周重新同步
flarum/abandoned-extensions 列表,提供了一个可按需触发的 “立即检查” 按钮,并在已安装的扩展变为废弃状态时发送管理员通知。
- 新增
forum-widget 扩展分类。在扩展列表中的“主题”和“语言包”之间,新增了一个用于小部件风格扩展的分类。
- 新增“存在频道”(Presence Channel)授权扩展器。实时扩展(realtime)获得了一个新的
Realtime::authorizePresenceChannel 扩展器,允许扩展在 WebSocket 认证层控制对“存在频道”的访问权限。
🛠️ 修复与打磨
📱 前端与移动端
- 在移动端撰写回复时,
ReplyPlaceholder 组件会显示用户头像和徽章。
- 返回导航不再丢失已加载页面或滚动位置——
PaginatedListState 现在通过值而非引用比较参数。
- 恢复
UserCard 控件图标,使移动端的控制按钮重新可见。
- 管理后台的导航下拉菜单在移动端不再闪烁。
- 修复管理后台
StatusWidget 在移动端的布局——项目现在以网格形式排列,工具按钮横跨整行。
- 修复 FontAwesome Kit 不再覆盖隐藏图标上的
display: none 样式。同时清理了标签选择和订阅下拉菜单的标记。
- 修复某些布局中底部页面内边距被裁剪的问题。
- 修复单选按钮组冲突——同一页面上的多个单选按钮组不再共享相同的
name 属性并相互干扰。
- 全新安装时,管理后台的头像驱动选择器现在会显示正确的默认值,废弃扩展同步状态消息也有了合适的内边距。
🧭 路由与 URL
- URL 末尾的斜杠不再导致 404 错误。
ResolveRoute 现在会在分派请求前去除末尾的斜杠,因此 /d/123-foo/ 和 /d/123-foo 的解析结果相同。
- 名称格式错误的扩展不再引发 PHP 警告。
ExtensionManager 现在会跳过不符合 供应商/包名 格式的包名,而不是在 nameToId() 函数中产生“未定义数组键”的警告。
🏷️ 标签扩展
bypassTagCounts 权限现在对非管理员用户也生效——之前的检查使用了仅限管理员的快捷方式,而实际上应该调用 hasPermission 方法。
- 标签首页的元描述现在会使用你的论坛描述(仅在未设置描述时回退使用 “All Tags” 的翻译)。
📌 置顶扩展
- 修复了
is_unread_sticky 子查询中 id 列歧义的问题——那些需要关联讨论表的扩展(如 byobu)不再会因为 MySQL 报“列歧义”错误而中断。
🔌 API 与序列化
- 属性字段现在能正确通过
serializeValue 方法处理——修复了一个长期存在的 Bug,即 allowSignUp 这类布尔值之前被作为字符串输出。
- 当类型为
Str 转换的属性返回数组时,数组值得以保留,避免了扩展中出现 “Array to string conversion” 错误。
Arr::serialize() 现在能正确处理如 MessageBag 这类实现了 JsonSerializable 接口的对象。
💬 社区用语
- 将用户界面中的一处 “community” 措辞替换为 “forum” 以保持一致性。
🌱 生态系统已准备就绪
rc.1 是向扩展生态系统发出的信号:API 已经稳定。如果你维护着一个扩展,现在是时候发布你兼容 2.x 的版本了。
语言包——@rob006 一直在协调语言包的更新。如果你维护着某个翻译,请关注相关的讨论帖。
Flarum 之友 (FoF)——FoF 扩展目录已几乎完全覆盖 2.x 版本。感谢所有相关贡献者。
扩展开发者——在 rc.1 到稳定版之间,我们正在优先解决最后的兼容性障碍。如果核心代码中存在阻碍你发布扩展的问题,请提交 issue。
🚀 亲自尝试
- 在线演示:nightly.flarum.site,每日重建
- 就在此处:discuss.flarum.org 正在运行 rc.1
- 更新你的安装:
composer update -W,然后执行 php flarum migrate,php flarum cache:clear,以及 php flarum assets:publish(请务必先备份,并在本地或预发布环境中测试)
💙 致谢
感谢所有为此版本贡献代码、报告 Bug 以及测试测试版的各位。
特别感谢 @ClaudiusH——他投入了大量时间运行每日构建版本,在整个测试版周期中不断发现大大小小的问题,并不知疲倦地维护德语语言包。本版本中很大一部分打磨工作都源于他的报告。谢谢你,Claudius。
📋 完整更新日志
新增 (Added)
- (core) 在扩展管理页面添加“重置设置”按钮及确认弹窗,由
DELETE /api/settings 和 Settings\Event\Reset 事件支持 (@IanM #4522)
- (core) 新增
forum-widget 扩展分类 (@IanM #4543)
- (core) 支持 HiDPI 头像 srcset — 上传时生成 @2x/@3x 变体,并在用户资源中暴露
avatarSrcset (@IanM #4555)
- (core) 废弃扩展列表每周自动同步,并附带管理员通知和手动“立即检查”按钮 (@IanM #4560)
- (realtime) 新增
Realtime::authorizePresenceChannel 扩展器,用于控制“存在频道”的访问权限 (@IanM #4573)
安全 (Security)
- (core) 在提交密码重置令牌时强制执行过期检查 (@IanM #4550)
- (core) 更改密码时使现有会话失效 (@IanM #4551)
- (core) 请求新重置时删除旧的密码令牌 (@IanM #4552)
- (core) 强化通过 URL 获取头像的 Guzzle 客户端 — 禁用重定向,添加超时和大小限制 (@IanM #4553)
- (core) 通过共享的
AbstractImageValidator 验证 Logo、favicon 和深色模式 Logo 的上传 (@luceos #4579)
修复 (Fixed)
- (core) 修复扩展名缺少
供应商/包名 格式时引发 PHP 警告的问题 (@IanM #4510)
- (core) 在路由分发前去除 URI 末尾的斜杠 (@IanM #4511)
- (core) 修复底部页面内边距不正确的问题 (@IanM #4518)
- (core)
Api\Serializer 属性字段现在会经过 serializeValue 处理,因此布尔值不再被序列化为字符串 (@IanM #4530)
- (core)
PaginatedListState::paramsChanged() 使用值比较,使返回导航能保留已加载页面和滚动位置 (@IanM #4532)
- (core) 修复在移动端撰写状态时,
ReplyPlaceholder 组件显示头像和徽章 (@IanM #4533)
- (core) 在
Attribute::serializeValue 中保留数组值,避免为 Str 类型属性返回数组的扩展出现“数组转字符串”错误 (@IanM #4534)
- (core) 小幅正确性和可访问性修复 — 序列化器元数据缓存、队列异常处理器、
@hasSection 指令、复选框 inputAttrs、表单组 Switch 的 aria-describedby (@IanM #4562)
- (core) 恢复
UserCard 上的控件图标,使移动端的控制按钮可见 (@IanM #4568)
- (core) 移除
FormGroup 中硬编码的单选按钮 name,使多个单选按钮组可以共存 (@rafaucau #4571)
- (core) 防止 FontAwesome Kit 覆盖隐藏图标元素上的
display 样式 (@IanM #4575)
- (admin) 改进仪表盘中
StatusWidget 在移动端的布局 (@IanM #4531)
- (admin) 修复头像驱动默认值以及废弃扩展同步消息的内边距 (@IanM #4567)
- (admin) 修复移动端导航下拉菜单闪烁的问题 (@luceos #4578)
- (sticky) 在
is_unread_sticky 子查询中限定有歧义的 id 列,避免需要关联讨论表的扩展出错 (@IanM #4520)
- (tags) 在
bypassTagCounts 中使用 hasPermission,使该权限对受限标签下的非管理员用户生效 (@IanM #4539)
- (tags) 在标签首页使用论坛描述作为元描述 (@IanM #4558)
变更 (Changed)
- (core) 将用户界面中的一处 “community” 措辞替换为 “forum” 以保持一致性 (@luceos #4580)
- (webpack-config) 从配置中移除已弃用的 Babel 插件 (@rafaucau #4498)
性能 (Performance)
- (core) 消除讨论列表中的 N+1 查询 (@IanM #4508)
- (core) 为
notifications 表添加复合索引,修复慢速的未读计数查询 (@IanM #4509)
- (core) 前端性能改进 — 预连接提示、
fetchpriority、修复无样式内容闪烁 (FOUC)、视口设置 (@IanM #4561)
- (tags) 在
TagFilter 中通过单次批量查询解析标签别名 (@IanM #4563)