Taro 1.0系列:taro build原理分析

众所周知,taro-cli是Taro脚手架初始化和项目构建的的命令行工具,它的实现原理,相信你们从Taro 技术揭秘:taro-cli这篇文章中已经有所了解;本文将对其中的项目构建build命令进行分析,从cli层面了解taro构建的过程到底作了什么;前端

build命令的注册

在执行npm install -g @tarojs/cli时,npm经过读取package.json文件中的bin字段,将taro这个命令注册到[prefix]/bin中做为全局命令;
若是在当前项目目录下,执行npm install @tarojs/cli,则会将taro这个命令注册到./node_modules/.bin/底下做为本地命令;node

// package.json
"bin": {
  "taro": "bin/taro"
}

因为npm config get prefix/usr/local,因此全局命令将会被注册到/usr/local目录底下,经过symlink符号连接的方式,使得/usr/local/bin/taro指向/usr/local/lib/node_modules/@tarojs/cli/bin/tarowebpack

bin/taro文件做为taro-cli的入口,内部使用commander.js来解析命令中的参数,而且支持git风格的子命令处理,能够根据子命令自动引导到[command]-[subcommand]格式命名的执行文件; git

因此当执行taro build命令时,则被commander.js自动引导到bin/taro-build文件下,继而执行bin/taro-build的逻辑;es6

build命令的分发

taro build命令功能很是多,它可以支持:web

  • 一、构建H5
taro build --type h5
  • 二、构建小程序及小程序插件,支持weapp/swan/alipay/tt/qq/jd类型;
// 小程序
taro build --type weapp
// 小程序插件
taro build --plugin weapp
  • 三、构建UI库;
cross-env TARO_BUILD_TYPE=component taro build --ui

taro-build接收--type参数的值,接收到的结果交由dist/build.jsbuild函数进行判断,经过判断不一样type的值,决定执行对应平台构建类型的逻辑,例如,当--typeh5时,则执行dist/h5/index.js文件中build函数的逻辑;当--typeweapp时,则执行dist/mini/index.js文件中build逻辑;npm

h5的构建逻辑

h5的构建流程主要通过:源代码 => 中间代码 => 目标代码的转换; 其中:json

  • 源代码:通常是指src目录底下的代码,若是config中有配置sourceRoot,则源代码入口就为sourceRoot
  • 中间代码:指.temp目录下的代码,由taro-build实现的中间流程,主要经过babel实现中间代码的转换和生成;
  • 目标代码:指最终运行在浏览器的代码,通常指dist目录下的代码,若是config中配置outputRoot,则目标代码将输出在outputRoot

因此,三种代码间的转换关系能够用下图表示:redux

taro-build-workflow

taro-build帮助将源代码转换成中间代码,并保存在.temp文件夹中,中间代码再交由webpack进行打包构建生成目标代码;小程序

中间代码的生成

为何会有中间代码生成这个步骤呢,这是由于:

  • 直接将源代码交由webpack进行编译,会出现部分方法的缺失、页面没法找到等的问题;
  • Taro须要根据构建平台的类型进行一系列的转换,并导入对应平台的核心包;
  • 还须要根据工程或者页面的config源代码进行转换,并插入一些关键代码

中间代码的生成流程须要转换的代码主要以src目录下的代码为主,并且只分析和转换js和ts的文件,由于涉及到代码的分析,因此借助了babel工具链,例如babel-corebabel-traversebabel-typesbabel-template等核心包中的方法进行处理,主要流程以下:

  • 一、区分是否为js或ts,是则进行分析,不然直接复制;
  • 二、分析文件是否为ENTRY文件PAGE文件NORMAL文件,分类完成,则交由对应的处理函数进行处理;
  • 三、处理解析ENTRY文件
  • 四、处理解析PAGE文件NORMAL文件
  • 五、处理完后的代码生成到.temp文件夹中;
  • 六、调用webpack-runner,对.temp文件的代码进行处理,生成到dist文件夹中;

taro-build-h5

ENTRY文件的分析

ENTRY类型的文件,由processEntry函数处理,经过babel-traverse中的traverse方法对不一样类型的AST节点进行分析,其中涉及到不少细节,主要流程以下:

  • 一、解析config这个ClassProperty节点的内容,获取pagessubPages;
  • 二、依赖纠正:主要转换tarojs/tarotarojs/mobxtarojs/redux相关依赖为tarojs/taro-h5tarojs/mobx-h5tarojs/redux-h5;转换ImportDeclaration节点中的alias别名;引入Nervjs核心包;
  • 三、在render函数中,加入页面的Router组件(根据pagessubPages),Provider组件,Tabbar组件;
  • 四、引入taro-router相关代码;

taro-build-h5-entry

PAGE文件和NORMAL文件的分析

PAGE类型NORMAL类型的文件,由processOthers函数处理,也是经过babel-traverse中的traverse方法对不一样类型的AST节点进行分析,这里只列出主要流程:

  • 一、依赖纠正:主要转换tarojs/tarotarojs/mobxtarojs/redux相关依赖为tarojs/taro-h5tarojs/mobx-h5tarojs/redux-h5;转换ImportDeclaration节点中的alias别名;引入Nervjs核心包;
  • 二、解析config这个ClassProperty节点的内容,获取配置项,对页面添加相关的组件和函数,例如PullDownRefresh组件和onPageScroll方法;
  • 三、导出纠正:当前类的nameExport纠正为defaultExport,例如:当前文件page-index.js
// 纠正前
export class PageIndex extends Component {
  ...
}

// 纠正后
class PageIndex extends Component {
  ...
}

export default PageIndex;
  • 四、声明纠正:当前ClassExpressionClassDeclaration中,在没有identifier的状况下,添加默认的identifier_TaroComponentClass
// 纠正前
export default class extends Component {
  ...
}

// 纠正后
export default class _TaroComponentClass extends Component {
  ...
}

webpack-runner逻辑

中间代码生成后,缓存在.temp文件夹底下,而且做为webpack-runner的入口文件,taro-build在完成buildTemp的流程后,就会继续执行调用webpack-runner的逻辑;webpack-runner的逻辑实际上就是根据定义好的webpack的配置,生成目标代码的流程,后面将会有单独的一篇文章详述相关配置,这里不作再多的描述;

小程序的构建逻辑

taro-build的小程序构建逻辑不存在中间代码的生成,而是直接由源代码生成小程序能运行的目标代码;这里的源代码是指遵循React规范的taro代码,这种代码在小程序的容器中是没法直接运行的,因此须要经过taro-build转换成小程序可运行的代码,所以在这个流程中涉及大量的AST语法解析和转换

小程序的构建流程主要分三步完成(固然这里还有不少细节,但本文暂不详细阐述):

  • 构建入口:指构建sourceDir指定的文件,默认是app.jsx文件,构建的逻辑由buildEntry函数完成;
  • 构建页面:指构建在app.jsx文件中的config.pages配置好的页面文件,主要由buildPages函数完成;
  • 构建组件:指构建页面文件中依赖的组件,主要由buildSingleComponent函数完成;

构建流程须要依赖taro-transformer-wx包去解析JSX语法,已经对源代码的AST语法树,进行代码插入和转换;

buildEntry逻辑

构建入口的逻辑大概以下:

  • 一、调用taro-transformer-wx中的wxTransformer方法转换JSX语法
  • 二、将app.jsx中的es6语法经过babel转换为es5,而且引入taro-weapp核心包;
  • 三、经过AST转换,插入调用taro-weapp包中createApp函数的语句;
  • 四、生成app.jsonapp.jsapp.wxss文件;

buildPages逻辑

构建页面的逻辑大概以下:

  • 一、调用taro-transformer-wx中的wxTransformer方法转换JSX语法
  • 二、将页面js中的es6语法经过babel转换为es5,而且引入taro-weapp核心包;
  • 三、经过AST转换,插入调用taro-weapp包中createComponent函数的语句;
  • 四、编译页面所依赖的组件文件,由buildDepComponents函数实现;
  • 五、生成页面对应的page.jsonpage.jspage.wxsspage.wxml文件;

buildComponent逻辑

构建组件与构建页面相似,但多了递归的步骤,其逻辑大概以下:

  • 一、调用taro-transformer-wx中的wxTransformer方法转换JSX语法
  • 二、将组件js中的es6语法经过babel转换为es5,而且引入taro-weapp核心包;
  • 三、经过AST转换,插入调用taro-weapp包中createComponent函数的语句;
  • 四、递归编译组件所依赖的组件文件,由buildDepComponents函数实现;
  • 五、生成页面对应的page.jsonpage.jspage.wxsspage.wxml文件;

taro-transformer-wx

taroJSX解析到小程序模板的逻辑,单独拆成一个包taro-transformer-wx,里面涉及到大量的AST解析和转换,本文因为篇幅的关系,暂时不详细分析,但愿后面会有单独的文章去分析小程序AST转换的流程,敬请期待;

结语

总的来讲,从cli层面去看taro的构建流程,会发现为了兼容多平台,taro会使用较多的AST解析和转换,帮助将React规范的taro代码转换到对应平台可以运行的代码;这里也告诉咱们,做为一个前端er,学习和掌握AST相关知识,能让你看到更大的世界!

最后,本文做为一篇原理分析的文章,若有疏漏以及错误,欢迎你们批评指正!

相关文章
相关标签/搜索