在分析 Taro 4.0.7 的源码时,我们可以从其核心的 monorepo 结构出发,理解不同子包的作用,以及 Taro 的多端执行过程和插件机制。
1. 核心 Monorepo 子包及对应作用
Taro 采用了 monorepo 结构,将多个功能模块拆分为不同的子包,便于管理和开发。以下是 Taro 4.0.7 中的一些核心子包,按照编译时和运行时进行分类:

2. Taro 多端执行的全过程
Taro 的多端执行过程包括项目的编译和执行两个阶段。
以下是从编译到执行的全过程,结合子包进行讲解:
2.1. 编译阶段
1. 项目初始化
- 使用 @tarojs/cli 创建项目,生成基本目录结构和配置文件。
2. 代码编译
根据配置文件,选择相应的编译插件(如 @tarojs/plugin-platform-weapp 或 @tarojs/plugin-platform-h5)进行编译。
编译过程中,使用 Babel 等工具将 ES6+ 代码转化为兼容的 JavaScript 代码。
根据 process.env.TARO_ENV 进行条件编译,移除不适用于当前平台的代码。
3. 生成产物
- 编译完成后,生成的代码文件会被放置在 /dist 目录下,供后续使用。
2.2. 执行阶段
1. 应用启动
- 用户通过相应的平台(如微信小程序、H5)访问应用。
2. 运行时解析
- 运行时库(如 @tarojs/taro)加载并解析应用的入口文件。
- 初始化路由管理(通过 @tarojs/router),处理页面的跳转和状态管理。
3. 组件渲染
通过 @tarojs/components 进行组件的创建和渲染,确保组件在各个平台上呈现一致的效果。
运行时执行与平台相关的特定逻辑,如事件绑定、样式处理等。
4. 用户交互
处理用户的交互事件,通过 API 与底层平台进行数据交换,更新视图。
2.3. 执行过程时序图

编译执行过程:

3. 核心原理代码说明
3.1. 编译时处理机制
3.1.1. 代码解析阶段
1. AST解析与处理
// 源代码
function Index() {
return (
Hello World!
)
}
// 解析为AST后的核心节点
{
type: "Program",
body: [{
type: "FunctionDeclaration",
id: { type: "Identifier", name: "Index" },
body: {
type: "ReturnStatement",
argument: {
type: "JSXElement",
// ... JSX节点信息
}
}
}]
}
2. 条件编译处理
// 源代码
if (process.env.TARO_ENV === 'weapp') {
require('./weapp.js')
} else if (process.env.TARO_ENV === 'h5') {
require('./h5.js')
}
// 编译后(以微信小程序为例)
require('./weapp.js')
3. 依赖分析
建立模块依赖图
识别循环依赖
分析未使用代码
处理动态导入
3.1.2. 代码转换阶段
1. 组件转换
// React组件
Hello
// 转换后的微信小程序
Hello
2. API转换
// Taro API
Taro.showToast({ title: 'Hello' })
// 转换后(微信小程序)
wx.showToast({ title: 'Hello' })
// 转换后(H5)
Toast.show({ content: 'Hello' })
3. 样式转换
// 源样式
.container {
display: flex;
transform: scale(0.5);
.title {
font-size: 14px;
}
}
// 转换后
.container {
display: -webkit-flex;
display: flex;
-webkit-transform: scale(0.5);
transform: scale(0.5);
}
.container .title {
font-size: 28rpx; // 小程序单位转换
}
3.1.3. 代码生成阶段
1. 目标平台代码生成
// 生成配置文件 (app.json)
{
"pages": [
"pages/index/index"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff"
}
}
// 生成页面配置 (index.json)
{
"usingComponents": {
"custom-component": "../../components/custom-component/index"
}
}
2. 静态资源处理
图片资源转换与优化
字体文件处理
媒体资源处理
3.2. 运行时处理机制
3.2.1. 框架运行时
1. 生命周期映射表
const LIFECYCLE_MAPPING = {
// React生命周期 -> 小程序生命周期
componentDidMount: 'onLoad',
componentDidShow: 'onShow',
componentDidHide: 'onHide',
componentWillUnmount: 'onUnload'
}
2. 事件系统处理
// 事件对象标准化
function createEvent(event) {
const { type, target, currentTarget, detail } = event
return {
type,
target: {
id: target.id,
dataset: target.dataset
},
currentTarget: {
id: currentTarget.id,
dataset: currentTarget.dataset
},
detail,
timestamp: Date.now()
}
}
3.2.2. 组件运行时
1. 组件映射机制
const ComponentsMapping = {
// React组件 -> 小程序组件
View: 'view',
Text: 'text',
Button: 'button',
Image: 'image'
}
2. 属性转换处理
function processProps(props) {
const newProps = {}
Object.keys(props).forEach(key => {
// className -> class
if (key === 'className') {
newProps.class = props[key]
}
// onClick -> bindtap
else if (key === 'onClick') {
newProps.bindtap = props[key]
}
// style对象处理
else if (key === 'style' && typeof props[key] === 'object') {
newProps.style = processStyle(props[key])
}
else {
newProps[key] = props[key]
}
})
return newProps
}
3.2.3. 状态管理运行时
1. 状态更新机制
class Store {
constructor() {
this.state = {}
this.observers = new Set()
}
setState(newState) {
this.state = { ...this.state, ...newState }
this.notify()
}
notify() {
this.observers.forEach(observer => observer(this.state))
}
}
2. 数据流管理
// Redux集成示例
function connectComponent(Component) {
return class Connected extends Taro.Component {
componentDidMount() {
store.subscribe(this.handleStoreChange)
}
handleStoreChange = (state) => {
this.setState(state)
}
render() {
return
}
}
}
3.3. 平台差异化处理
3.3.1. API适配层
// API适配示例
const apiDiff = {
weapp: {
showToast: wx.showToast,
getStorage: wx.getStorage
},
alipay: {
showToast: my.showToast,
getStorage: my.getStorage
},
h5: {
showToast: (options) => Toast.show(options),
getStorage: (options) => localStorage.getItem(options.key)
}
}
// 统一调用接口
function callApi(name, options) {
const api = apiDiff[process.env.TARO_ENV][name]
return api(options)
}
3.3.2. 样式适配处理
// 样式处理函数
function processStyle(style) {
const { platform } = process.env
// 单位转换
function transformUnit(value) {
if (typeof value === 'number') {
return platform === 'h5' ? `${value}px` : `${value}rpx`
}
return value
}
// 前缀处理
function addVendorPrefix(property) {
const needPrefix = ['transform', 'transition', 'animation']
if (needPrefix.includes(property)) {
return [
`-webkit-${property}`,
`-moz-${property}`,
`-ms-${property}`,
property
]
}
return [property]
}
return Object.entries(style).reduce((acc, [key, value]) => {
const properties = addVendorPrefix(key)
properties.forEach(prop => {
acc[prop] = transformUnit(value)
})
return acc
}, {})
}
3.4. 运行整体流程图

4. Taro 插件与端支持插件机制
4.1. 插件机制
Taro 的插件机制使得开发者可以通过插件的方式扩展 Taro 的功能。这包括编译时的支持插件和运行时的功能扩展。插件的设计遵循以下原则:
独立性: 插件之间独立,彼此不影响,便于维护和扩展。
灵活性: 开发者可以选择性地添加或移除插件,适应不同项目需求。
4.2. 端支持插件
Taro 提供了多种端支持插件,如 @tarojs/plugin-platform-weapp 和 @tarojs/plugin-platform-h5,这些插件负责处理特定平台的编译逻辑。
开发者也可以基于现有的插件进行扩展,支持更多平台。
5. 补充资料
Taro 文档:https://docs.taro.zone/docs/
Taro 案例合集:https://github.com/NervJS/awesome-taro
编译原理相关:https://taro-docs.jd.com/docs/implement-note#%E7%BC%96%E8%AF%91%E6%97%B6
Taro 物料市场:https://taro-ext.jd.com/
Taro React Hooks:https://docs.taro.zone/docs/apis/taro.hooks/useDidShow
Taro plugin:https://github.com/NervJS/taro-plugin-mock
浙公网安备 33010602011771号