Skip to content

架构演进:编译时到运行时

基于 Taro 4.x · 核于 2026-07

速查

  • 核心叙事:Taro 从「重编译时」(1/2 代)到「重运行时」(3 代彻底重写)的一次范式切换,4 代再叠加 Vite + CompileMode + 鸿蒙
  • Taro 1/2(2018-2019,重编译时):类 React 私有 DSL,把 JSX 静态编译成小程序 wxml;语法限制多(如只能 Array#map、JSX 只能写在 render),框架能力被阉割
  • Taro 3(2020,3.0.0 GA 2020-07-01,重运行时·彻底重写)不再是私有 DSL,直接跑真正的 React/Vue/Preact 运行时,靠模拟 DOM/BOM 让框架「以为自己在浏览器里」,语法限制大幅解除
  • Taro 4(2024,Beta 2024-04 / 首个正式版 v4.0.3 约年中;最新 v4.1.8):运行时 + Vite 编译内核 + 小程序 CompileMode + 三条鸿蒙路线
  • 权衡:重编译时=产物小、启动快,但框架能力受限、多框架维护成本高;重运行时=完整框架能力 + 生态复用,代价是运行时开销(靠 setData 优化、CompileMode 补偿)
  • Taro 3 运行时三件套@tarojs/runtime(精简版 DOM/BOM + 事件系统 + 桥接层)、@tarojs/react(用 react-reconciler 自建 renderer,不用 ReactDOM)、编译期 @tarojs/mini-runner + @tarojs/taro-loader
  • 渲染链路:逻辑层跑出 Taro DOM 树序列化setData 推给渲染层 → 利用小程序模板可互相引用特性,把每个节点渲成 <template> 递归引用拼出 UI(模板集中在 dist/base.xml

一、四代架构一览

版本年份架构特征
Taro 1.x2018重编译时类 React 私有 DSL;把 JSX 静态编译成小程序模板(wxml);语法限制多(只能 Array#map、JSX 只能写在 render);开发体验受限
Taro 2.x2019编译时为主,引入部分运行时改善 Vue 支持、扩更多端;仍有 DSL 限制
Taro 3.x2020(3.0.0 2020-07-01 GA)重运行时(彻底重写)不再是私有 DSL,直接跑真正的 React/Vue/Preact/Nerv 运行时;靠模拟 DOM/BOM 让框架「以为自己在浏览器里」,语法限制大幅解除
Taro 4.x2024(Beta 2024-04,v4.0.3 约年中;最新 v4.1.8)运行时 + Vite + 鸿蒙新增 Vite 编译内核、小程序 CompileMode(编译模式 / 混合编译,性能优化)、三条鸿蒙路线(先 ArkTS 后 C-API)

二、为什么从编译时转向运行时

重编译时(Taro 1/2) 的思路是:把你写的类 React 代码在构建期静态分析、翻译成小程序原生模板(wxml + js)。

  • 优点:产物小、启动快,几乎没有运行时开销。
  • 致命缺点:为了让编译器能静态分析,必须限制语法(私有 DSL),框架的动态能力被大量阉割;同时要为每个框架、每个端各写一套编译规则,维护成本极高

重运行时(Taro 3+) 反过来:不翻译代码,而是把整个框架运行时搬进小程序——

  • 优点:跑的是原汁原味的 React/Vue 运行时,语法限制基本消失,能复用框架生态(Hooks、状态库、社区组件)。
  • 代价:引入运行时开销(框架 diff、setData 传输),需要靠工程手段(减少 setData、CompileMode 等)补偿。

Taro 3 的这次「彻底重写」是整个项目的分水岭,也是面试高频考点。

三、Taro 3 运行时原理

核心是让运行在逻辑层的 Web 框架「以为自己在浏览器里」,再把它产出的「DOM」桥接到小程序渲染层。

三件核心包

  • @tarojs/runtime:核心适配层,实现精简版 DOM / BOM API、事件系统,以及「Web 框架 ↔ 小程序框架」的桥接层。
  • @tarojs/react:用 react-reconciler 自建 renderer(而非体积庞大的 ReactDOM),把 React 渲染到 Taro 的模拟 DOM 上。
  • 编译期@tarojs/mini-runner(webpack 配置 / loader / PostCSS)、@tarojs/taro-loader(转换组件引用)。

渲染链路

  1. React/Vue 在逻辑层正常运行,操作的是 @tarojs/runtime 提供的模拟 DOM,产出一棵 Taro DOM 树
  2. Taro 把这棵树的变化序列化成普通数据。
  3. 通过小程序的 setData 把数据推给渲染层
  4. 渲染层利用小程序模板可以互相引用的特性:把每一个 DOM 节点渲染成一个 <template>,再递归引用模板拼出最终 UI(这些模板集中生成在 dist/base.xml)。
逻辑层 (JS 线程)                        渲染层 (WebView)
┌─────────────────────┐                ┌──────────────────────┐
│ React/Vue 运行时      │                │  base.xml 递归模板     │
│   ↓ 操作模拟 DOM      │   setData      │   ↑ 按数据递归渲染节点  │
│ @tarojs/runtime      │ ─────────────▶ │  bind 绑定事件         │
│   Taro DOM 树 → 序列化 │  (序列化数据)   │   ↓ 冒泡回逻辑层        │
└─────────────────────┘ ◀───────────── └──────────────────────┘
                          事件回传

事件

渲染层用小程序原生 bind 绑定事件 → 事件冒泡回逻辑层的 Taro 事件系统 → 再分发到 React/Vue 的 onXxx 回调。这就是为什么 Taro 里事件都写成 on 前缀(见开发模型)。

四、Taro 4 在运行时之上加了什么

Taro 4 没有推翻运行时模型,而是在其上做增强:

  • Vite 编译内核compiler: 'vite'(自 v4.0 起),更快的冷启动与 HMR;纯血鸿蒙 C-API 仅支持 Vite
  • CompileMode(编译模式 / 混合编译):小程序端性能优化——把部分本可静态确定的运行时逻辑在编译期静态化,减少运行时 setData 与递归模板开销,相当于在「重运行时」里局部找回「编译时」的红利。
  • 三条鸿蒙路线:先 ArkTS 方案、后 C-API 纯血方案(见纯血鸿蒙三路线)。

工程配置(compilerconfig/index.ts、CLI)详见工程与构建配置