Linear 是很多团队在用的项目管理工具。它的快是出了名的,页面切换没有加载、数据操作没有等待、感觉不像一个 Web 应用。
这个团队最近发了一篇技术文章,详细拆解了他们怎么做到这么快的。不是单一技巧,而是从数据库到构建、从加载到交互的全链路优化。
最核心的一条原则是:UI 响应速度不应该依赖网络延迟。

浏览器就是数据库
传统应用的操作流程是:用户点击 → HTTP 请求 → 服务器查库 → 返回 → 浏览器重绘。一次简单的修改,三百毫秒就没了。
Linear 换了个思路。它把数据库搬到了浏览器,使用 IndexedDB 在本地存储数据,UI 直接读本地数据。变更先在本地应用,再异步推送到服务器,服务器通过 WebSocket 把增量广播给其他客户端。
所以你操作的时候完全没有等待。界面立刻反映你的操作,网络请求在背后悄悄进行。
这不是什么新技术,但真正做到这个级别的产品不多。关键在于,Linear 把这种架构贯彻到了每一个交互细节里。
构建工具迭代了四轮
一个很多人没注意到的细节:Linear 的构建工具先后换了四轮,Parcel → Rollup → Vite → Rolldown。
每次切换都带来了实实在在的收益。最终成果是:代码量减少 50%,压缩后体积减少 30%,冷加载页面提速 10% 到 30%。最夸张的是活跃问题视图的首屏时间,在 Safari 上下降了 59%。
他们还做了一个大胆的决定:放弃旧浏览器支持。没有 polyfill、没有 ES5 兼容、没有 nomodule fallback。这意味着代码里不需要塞入大量兼容代码,体积自然就小了。
虽然总 JavaScript 约 21MB,但被拆成了数百个路由级代码块,按需加载。配合 modulepreload 预加载,在 HTML 头里列出所有依赖,浏览器在解析入口脚本前就并行下载,冷加载从串行瀑布变成了并行批处理。
你永远不知道一个 Web App 后跑了多少个 js 文件 😳
Service Worker 预缓存
Linear 的 Service Worker 预缓存了大约 1200 个资源。用户登录后,整个应用在几秒内就全部进入缓存。后续导航完全跳过网络,直接走缓存。
这还带来了一个副作用:支持离线使用。创建 issue、编辑内容、变更状态,即使没有网络也能完成,等网络恢复后再同步。
渲染哲学
数据层面还有一个巧妙的做法。Linear 使用 MobX 作为状态管理,每个模型属性都是独立的观察者。修改一个字段时,仅重新渲染读取该字段的组件。如果 50 条 issue 同时更新,也只重新渲染那 50 个单元格,而不是整个列表。
这意味着多人同时编辑同一个页面时,每个人看到的内容都是实时更新的,而且不会出现整个页面卡住的情况。

大家讨论
文章在 HN 上拿到 277 分、149 条评论。有不少人赞同,但也有不少不同的声音。
有人指出了乐观更新的另一面。throwaway7783 说:「最终一致性的数据库很难做。对 Linear 的用例也许还好,但如果你不确定更新有没有到达服务器——也就是你的队友——那就有问题。同步延迟在其他项目里给我造成过无数麻烦,所以我宁愿用同步方案。」
也有人觉得实际体验没吹的那么神。saagarjha 说:「我实际用下来 Linear 挺慢的。有一周如果不关标签页,过一阵 CPU 就跑到 100%。」HoyaSaxa 也说:「我们团队就在用 Linear,我确实是个异类,但我真的觉得 UX 不太好。页面加载是快,但经常看到数字在刷新,却没有任何加载中的视觉提示,让人不知道数据到底同步好没有。」
不过跟 Jira 比,大家还是认可的。Keyframe 说:「说实话之前我从来没觉得 Linear 快——跟大多数 Web 应用一样有点卡。但跟 Jira 比,那简直是光速。」
值得学的地方
Linear 分享的技术细节不少,但有几条是大多数团队可以立刻用的:
乐观更新。 用户操作后别等着网络返回才更新界面,先改界面再发请求。用 Tanstack Query 或者 SWR 都能实现。
放弃旧浏览器。 如果你的用户群不是 IE 用户,放弃旧浏览器兼容能省下大量代码体积。
内联关键样式。 把首屏要用的 CSS 直接放进 HTML 头,减少请求次数。
键盘快捷键。 Linear 的所有常用操作都有快捷键,配合命令面板(⌘K)搜索本地数据,完全不需要网络。
跳转原文可以查看分析文章,有更多细节可以学习和借鉴。
视野决定终点,与君共勉。如果本文对您有帮助,不妨动动手指点下 👍 和 💗,让更多人看到,谢啦!
欢迎关注 前沿信标。
夜雨聆风