Octane:把 React 心智模型交给编译器,丢掉虚拟 DOM 和依赖数组
项目速览:React 的编程模型,已编译。 Inferno 的后继者,将其性能第一的目标向前推进:
秒懂
- 它是什么?
- Octane 是 Inferno 的继任者,用编译器把 React 风格的组件直接变成 DOM 操作代码。它保留了 hooks 模型,却取消了依赖数组和规则 of hooks 的限制,适合追求性能又不愿离开 React 语法的团队。
- 适合谁用?
- Octane 适合两类人:一类是熟悉 React 但受够了手动维护 useEffect 依赖数组和 hooks 调用顺序限制的开发者,另一类是需要在服务端渲染和流式输出场景下追求低运行时开销的团队。不适合那些重度依赖 class 组件、Server Components 或 React 合成事件系统的项目,这些在 Octane 中明确不支持。
- 能商用吗?
- 可以。MIT 是宽松许可证:你可以使用、修改并销售基于它的软件,只需保留版权和许可证声明。
- 还在维护吗?
- 在维护。仓库在最近一天内有新的提交。
- 用什么语言写的?
- 主要是 TypeScript(依据 GitHub 的语言统计)。
以上回答依据项目的 GitHub 数据(最近同步于 2026年9月15日)和我们的分析,不构成法律意见。
开源项目深度解析
它解决什么问题:React 的开发体验,Inferno 的运行时开销
Octane 的定位很直接:你写 React 风格的组件,编译器在发布前把它们变成直接操作 DOM 的代码。没有虚拟 DOM,没有合成事件系统,没有 hooks 规则检查。它由 Dominic Gannaway 创建,此人也是 Inferno 的作者,并在 React、Lexical、Ripple、Svelte 上有过工作经历。目标用户是那些熟悉 React API、但觉得虚拟 DOM 的运行时开销和手动维护依赖数组是负担的团队。README 里明确说,React 的知识可以直接迁移,useState、useEffect、memo、context、portals、Suspense、transitions 这些 API 都有,且用一套大型行为测试套件逐项核对,覆盖情况记录在 docs/react-parity-coverage.md 中。这不是一个从零开始的新语法,而是对 React 模型的编译期优化。
编译器的核心机制:.tsrx 与模板指令
Octane 的编译发生在构建时。标准 JSX 可以直接用,但作者推荐 .tsrx 文件,它被称为 JSX 的精神继承者。.tsrx 增加了模板指令,比如 @if、@for、@switch、@try,这些指令会编译成键控快速路径。还有一个 @{ ... } 简写,把 setup 逻辑和输出放在一起。README 里给的 Counter 例子展示了这种写法:import { useState } from 'octane',然后在一个函数组件里用 @{ ... } 包裹状态声明和 JSX 输出。编译器会识别这些指令,生成高效的 DOM 更新代码。关键是,.tsrx 和 .tsx 可以在同一个应用里混用,并且可以跨边界导入。这意味着你可以逐步迁移现有 React 代码,而不是一次性重写。
依赖数组的消失:编译器从闭包推导依赖
Octane 最激进的设计是允许省略 useEffect、useMemo、useCallback 的依赖数组。编译器会分析闭包实际捕获了什么,包括稳定的 setter、dispatcher、refs 和 state getters,然后自动生成依赖列表。这消除了信号框架常用来吸引用户的那些手动簿记工作,但又没有离开 hooks 模型。如果你显式写依赖数组,它的语义和 React 完全一致。这个设计有一个隐含的代价:编译器的闭包分析必须足够聪明,能识别出哪些捕获是稳定的。如果分析出错,你可能得到错误的依赖行为,而且这种错误在编译期不一定能发现。README 没有说明这种推导失败时会怎样,这值得在实际项目中验证。
没有规则 of hooks,但有编译期检查
React 的 hooks 规则依赖调用顺序,而 Octane 改为按调用点跟踪。因此 hooks 可以放在 if 语句里,也可以放在提前 return 之后。唯一的限制是:在普通 JS 循环里写 hooks 会直接编译报错,因为每次迭代会共享同一个调用点槽位。正确做法是用 @for 指令,每个条目拥有独立的 hook 状态。这个设计比 React 的 lint 规则更严格,因为它是编译器强制执行的,而不是靠 ESLint 插件提醒。对于习惯了 React 的开发者,这需要一点思维转变,但它确实消除了运行时检查 hook 顺序的开销。
平台原生,不重新实现浏览器
Octane 没有合成事件系统,事件处理直接使用真实的 DOM 委托事件。受控表单组件基于原生事件,value 和 checked 的语义与 React 一致,但 onInput 在每次编辑时触发,onChange 在提交时触发,这更贴近浏览器的原生行为。refs 被当作普通属性处理,支持回调函数、对象,甚至数组形式。这种设计减少了运行时库的体积,也避免了合成事件带来的兼容性问题。但代价是,React 的合成事件跨浏览器一致性保证没有了。如果你的应用依赖合成事件提供的某些怪癖行为,Octane 可能不兼容。
并发渲染与流式 SSR:use() 和 Suspense 的处理
Octane 对 promise 的处理很特别。在渲染中使用 use() 不需要 cache() 包装,创建 promise 的表达式会在声明处自动 memoize,包括局部的 .then 链。独立的请求会同时启动,每个 Suspense 层级只挂起一次,并且当祖先还在挂起时,后代的 fetch 树会预取。这解决了 React 中常见的瀑布请求问题。服务端渲染支持流式输出,可以在 Node 或 web streams 上实现乱序 Suspense 刷新,也支持缓冲和静态渲染。水合是字节级稳定的,这意味着服务器和客户端生成的 HTML 必须完全一致。还有一个 Hydrate 组件,可以让服务器 HTML 保持可见但不激活,直到值得激活时才接管,并且默认把子组件拆分成独立的 chunk。
与 React 的互操作和边界
octane/react 包提供两个方向的双向兼容。ReactCompat 可以在 Octane 应用里渲染真正的 React 组件,要求匹配 React 和 React DOM 19.2+ 的 19 系列版本。OctaneCompat 则允许在 React 应用里嵌入 Octane 组件。这降低了迁移风险,你可以逐步替换。但 Octane 明确不支持 class 组件、Server Components 和合成事件系统,这些在文档 Differences from React 中列明。对于大型 React 项目,如果大量使用 class 组件或 Server Components,迁移成本会很高。
安装、工具链与维护成本
安装很简单。npm create octane my-app 会生成一个可运行的项目,--template spa 是纯客户端,--template fullstack 包含路由、流式 SSR、水合和生产构建。在现有项目里可以用 pnpm dlx @octanejs/cli init 自动配置,包括 TypeScript 设置。手动安装只需要 pnpm add octane @octanejs/vite-plugin,然后在 vite.config.ts 里加上 octane() 插件。Rspack 和 Rsbuild 也支持。注意,需要 Node.js 22.22.2 或更新版本。许可证是 MIT,没有额外的使用限制。维护成本方面,项目最近一次推送是 2026 年 8 月,发布了 0.1.49 版本,还处于 0.x 阶段,API 可能变动。编译器的依赖推导逻辑是核心复杂度,如果升级版本后行为变化,可能需要回归测试。
编辑结论
Octane 适合两类人:一类是熟悉 React 但受够了手动维护 useEffect 依赖数组和 hooks 调用顺序限制的开发者,另一类是需要在服务端渲染和流式输出场景下追求低运行时开销的团队。不适合那些重度依赖 class 组件、Server Components 或 React 合成事件系统的项目,这些在 Octane 中明确不支持。在决定采用之前,先做两件事:第一,打开 docs/react-parity-coverage.md,对照你项目中用到的 React API 是否在覆盖列表里,尤其是 useContext、useTransition 这类容易出边界情况的功能;第二,用 npm create octane my-app 生成一个 fullstack 模板,实际跑一遍流式 SSR 和 Hydrate 组件的表现,确认字节级稳定的水合在你的真实网络条件下成立。Octane 的编译期依赖推导是它最大的卖点,也是最大的不确定性,你必须在自己的代码库上验证编译器推导出的依赖是否符合直觉。
社区笔记