Elk — Mastodon 客户端

为了验证 Vue Lynx 能承载真正产品级的应用,我们把 Anthony Fu 团队广受喜爱的 Mastodon Web 客户端 Elk 移植成了一个 原生 Mastodon 客户端。它能以游客身份浏览任意公开 Mastodon 实例 (默认 mas.to),支持时间线、会话串、个人主页、搜索、趋势、深色模式等。

在下方直接体验:Web 标签页通过 Lynx for Web 运行真实应用并连接线上 Mastodon 实例;切换到 二维码 标签页,用 Lynx Go / Lynx Explorer (安装方式见快速开始)扫码,即可在手机上原生运行 同一份 main.lynx.bundle

为什么 Elk 是一块试金石

Elk 是一个约 196 个组件、55 个页面、50 个 composable 的 Nuxt 3 应用。 Vue Lynx 没有 Nuxt(没有 SSR、文件路由、Nitro、自动导入),也没有 DOM —— 所以移植没有走 fork 路线,而是复用 Elk 与框架无关的层,在 Lynx 元件上重建 UI

结论说明
masto.js API 客户端✅ 原样复用fetchRequestAbortSignal 等自由标识符形式的 Web 全局变量通过 source.define 重写为 globalThis.* —— Lynx 后台线程的 eval 作用域中拿不到它们
内容解析管线content-parse.ts✅ 约 95% 原样ultrahtml 消毒 + 自定义表情 / markdown / 提及折叠等变换
内容渲染器content-render.ts♻️ 重定向输出AST 遍历逻辑不变;产出从 <p>/<a>/RouterLink 换成带点按导航的 <text>/<image>
分页器、时间线过滤、状态操作、搜索、缓存✅ 复用DOM 滚动触发 → 原生 <list>scrolltolower
虚拟滚动♻️ 替换Elk 的 DOM 虚拟滚动库(virtua)→ Lynx 原生复用型 <list>,代码反而更少
路由♻️ 重建Nuxt 文件路由 → 基于 createMemoryHistory 的显式 vue-router 路由表,路径形状保持一致,内容渲染器的提及/话题改写无需变更
所有模板♻️ 重建<div><view><span><text>@click@tap,Elk 的主题色板原样搬为 Lynx CSS 变量
图标♻️ 适配Elk 的 RemixIcon 图标集(i-ri:*)内联为着色 SVG data-URI

完整的功能对齐清单(包括刻意未移植的项与原因 —— OAuth 重定向、TipTap、 PWA、Shiki、blurhash 等)见 PRD.md, 架构对照见 PORTING.md, 与原版 elk.zone 的逐屏截图对比见 screenshots/

亮点

  • 内容渲染器是皇冠明珠:Mastodon 的嘟文以消毒后的 HTML 下发。Elk 把它解析成 AST 再渲染为 vnode;移植保持解析步骤逐字节不变,只替换 vnode 目标 —— 自定义表情变为行内 <image>,提及/话题变为可点按的 <text>,直接推入 vue-router 路由。
  • 原生虚拟化时间线:无限时间线是带 estimated-main-axis-size-px 提示的 Lynx <list>;masto.js Paginator 迭代与 Elk 的排序/缓冲逻辑原样驱动。
  • 深链:向 LynxView 传入 globalProps: { initialPath: '/mas.to/tags/caturday' } 即可让应用直接打开对应路由 —— 宿主应用处理通知点击时用的就是同一机制。
  • 游客 + 令牌会话:像 Elk 游客模式一样匿名浏览,或在设置中粘贴个人访问令牌, 解锁主页时间线、通知、发帖、转发与喜欢。