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相關知識,能讓你看到更大的世界!

最後,本文做爲一篇原理分析的文章,若有疏漏以及錯誤,歡迎你們批評指正!

相關文章
相關標籤/搜索