架构演进:编译时到运行时
基于 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.x | 2018 | 重编译时 | 类 React 私有 DSL;把 JSX 静态编译成小程序模板(wxml);语法限制多(只能 Array#map、JSX 只能写在 render);开发体验受限 |
| Taro 2.x | 2019 | 编译时为主,引入部分运行时 | 改善 Vue 支持、扩更多端;仍有 DSL 限制 |
| Taro 3.x | 2020(3.0.0 2020-07-01 GA) | 重运行时(彻底重写) | 不再是私有 DSL,直接跑真正的 React/Vue/Preact/Nerv 运行时;靠模拟 DOM/BOM 让框架「以为自己在浏览器里」,语法限制大幅解除 |
| Taro 4.x | 2024(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(转换组件引用)。
渲染链路
- React/Vue 在逻辑层正常运行,操作的是
@tarojs/runtime提供的模拟 DOM,产出一棵 Taro DOM 树。 - Taro 把这棵树的变化序列化成普通数据。
- 通过小程序的
setData把数据推给渲染层。 - 渲染层利用小程序模板可以互相引用的特性:把每一个 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 纯血方案(见纯血鸿蒙三路线)。
工程配置(
compiler、config/index.ts、CLI)详见工程与构建配置。