什麼是Taro
Taro 是一套遵循多端開發的解決方案。只需要一套代碼,就可以編譯轉換成 RN、H5、小程序、快應用多端的運行代碼,其運轉流程主要分為編譯時,運行時兩個階段。
Taro2(重編譯,輕運行)
- 編譯時:通過taro工具將Taro源代碼轉換成目標代碼
- 運行時:目標代碼運行時,通過運行時的庫去適配不同端
Taro3(輕編譯,重運行)
Taro3主要通過在小程序端模擬實現 DOM、BOM API 來讓前端框架直接運行在小程序環境中,而對於生命週期、組件庫、API、路由等差異,通過定義統一標準,在運⾏時會提供 React 和 Vue 對應的適配器進⾏適配,然後調⽤Taro提供的 DOM 和 BOM API, 最後把整個程序渲染到所有的⼩程序端上⾯。
編譯流程
Taro本質上是進行多端編譯和運行,而Taro的編譯主要依賴於webpack配置,Taro則通過mini-runner完成webpack配置的組裝,然後根據 webpack 配置生成編譯後的代碼。
tarojs/mini-runner的作用
- 負責根據開發者的編譯配置調整 webpack 配置
- 注入自定義的 插件 和 loader
- 調用 webpack 開啓編譯
- 修改 webpack 的編譯產物,調整最終的編譯結果
目錄結構
主流程(index)
主要分為兩個流程,根據項目配置生產webpack的構建配置,利用webpack進行代碼編譯。
基礎配置
base.config.ts 文件記錄基本配置信息,主要是Taro 構建過程中一部分 webpack 配置的初始化工作(包括文件擴展名、模塊解析路徑、別名等)。
自定義配置
buildConf.conf.ts 中主要負責配置一些構建過程中所需的插件、常量和選項,確保構建過程中能夠根據配置進行適當的處理和優化。
合併webpack配置
合併webpack配置,確保小程序項目在構建時能夠按照用户的配置和需求生成合適的 Webpack 配置。
分析配置
通過分析主包來進一步瞭解tarojs/mini-runner在其中的作用。
查看config配置
- projectName: 項目名稱
- date: 項目創建日期
- designWidth: 設計稿寬度,用於進行適配
- deviceRatio: 不同設備寬度的適配比例
- sourceRoot: 源代碼目錄
- outputRoot: 輸出目錄,根據環境變量進行不同的配置
- plugins: 配置Taro框架使用的插件
- env: 環境變量配置
- defineConstants: 常量配置
- copy: 複製文件的配置,將一些靜態文件複製到輸出目錄
- framework: 項目框架
- mini: 針對小程序的配置
- h5: 針對H5平台的配置
- alias: 路徑別名配置,簡化在代碼中的引用路徑
defineConstants
defineConstants 主要進行常量的相關配置。
首先將環境變量,靜態常量,運行時常量合併為一個常量對象definePlugin,通過getDefinePlugin 函數返回了一個配置好的 DefinePlugin 實例,definePlugin是Webpack的一個內置插件,用於替換代碼中的變量為其對應的值。
通過這個配置,Webpack 在構建時會將代碼中的 APPNAME 替換為 process.env.APPNAME 的值。同樣,其他常量也會按照相應的方式被替換。
copy
copy複製文件的配置,將一些靜態文件複製到輸出目錄,
- patterns: 一個數組,指定了需要拷貝的文件或目錄的規則
- options: 配置選項
不同環境拷貝不同的目標路徑,主要用於對地圖的適配。
在 patterns 數組中添加了一個額外的拷貝規則,將 plugin/doc 目錄拷貝到輸出目錄的 doc 目錄下,如果配置中存在copy 調取getCopyWebPackPlugin。
getCopyWebpackPlugin 函數接收一個包含 copy 配置的對象以及應用程序路徑 appPath。通過 CopyWebpackPlugin 創建實例,配置 patterns,將配置項中的相對路徑轉換為絕對路徑,確保正確的拷貝。返回創建的 CopyWebpackPlugin 實例。
alias
alias主要用於簡化在代碼中的引用路徑。
resolve 是一個配置選項,用於指定解析模塊請求的規則。alias 配置會被合併到 resolve 中。
在構建過程中,Webpack 將會使用這些別名來解析模塊的引入路徑。例如,當代碼中出現 import '@/ecoExpress/someModule' 時,Webpack 將會解析為 path.resolve(__dirname, '..', 'src/ecoExpress/someModule')。
mini
postcss
pxtransform 配置:
- enable: true 表示開啓對 CSS 中的 px 單位進行轉換
- config: 可以用於配置 pxtransform 的詳細選項,比如配置項的轉換規則
url 配置: - enable: true 表示開啓對樣式文件中的圖片、字體等資源的 URL 轉換
- config: { limit: 1024 } 限制轉換的資源大小,超過這個大小的資源將被單獨輸出文件,小於這個大小的資源將被轉換成 base64 編碼並嵌入樣式文件中
這個配置的目的是將小圖片、字體等資源直接轉換成 base64 編碼,減少網絡請求,提高小程序的加載速度。
cssModules 配置:
- enable: false 表示不開啓 CSS Modules 功能。
- config: 可以配置一些關於 CSS Modules 的選項,包括命名規則等
開啓了 CSS Modules,可以通過配置項進行定製化,CSS Modules 允許將 CSS 樣式作用域限制在組件內,避免全局樣式的污染。
查看config基礎配置,進行了一些預處理。
webpackChain
在 webpack 中,webpackChain 通常指的是一種鏈式調用的方式來配置 Webpack 的構建過程。在 Taro 中,webpackChain 主要是用於自定義和擴展 Webpack 配置的工具。
Taro 封裝了 webpack 的配置,提供了一些默認的配置,同時也允許開發者通過 webpackChain 自定義和擴展這些配置。這種鏈式調用的方式可以更方便地對 Webpack 配置進行修改和增強。
如下代碼可知,mini-runner 將內部 webpackChain 和開發者配置的 webpackChain 相結合,得到最終的webpackChain。
針對小程序進行配置。
先查看mini中的webpackChain,查看第一個插件 hitchFeCompontsImportPlugin,可以得出主要功能是匹配不同依賴路徑確定不同的配置。
multiPlatformPlugin,接着看下一個函數,這個方法的作用是為 Taro 項目配置 Webpack 的解析插件,限制只解析以 '@hb/' 開頭的模塊路徑,以支持 Taro 項目的多平台打包需求。
使用 webpack-bundle-analyzer 插件,並傳遞一個空數組 [] 作為配置(webpack-chain中 use的第二個參數,作為插件的配置,可以不填,但必須要是數組)。
使用自定義的 Stats 類創建的插件。這個插件的作用是在 Webpack 構建完成後將統計信息寫入一個文件(stats.json),以供進一步分析和處理。
- 使用 chain.optimization 配置 Webpack 的優化
- 調用 .minimizer() 方法,傳遞一個包含 TerserPlugin 實例的數組。TerserPlugin 用於壓縮 JavaScript 代碼
- extractComments: false,配置了禁止提取註釋的選項,以防止將註釋提取到單獨的文件中
optimizeMainPackage
配置項 optimizeMainPackage 控制了主包的優化,只有在構建目標環境是微信小程序(TARO_ENV === 'weapp')時才啓用。主要的目的是在微信小程序中優化主包的構建。
判斷 optimizeMainPackage.enable 是否為 true,如果為 true,則使用 getMiniSplitChunksPlugin 函數創建了一個插件實例,並將其配置合併了 optimizeMainPackage 和 fileType。這個插件的作用是對小程序主包進行分包優化。
Webpack 提供了 SplitChunkPlugin 進行分包優化。SplitChunksPlugin 插件可以將應用程序中共享的代碼拆分成單獨的塊,以便將其從應用程序代碼中分離出來,從而提高性能和加載速度。
miniCssExtractPluginOption
miniCssExtractPluginOption用於指定 Mini CSS Extract 插件的選項。,其中 ignoreOrder 主要是為了避免關於樣式引入順序的警告。當為 true 時,表示忽略 CSS 文件的引入順序,不會拋出關於引入順序的警告。
baseLevel
對於不支持模板遞歸的小程序(微信、QQ、京東小程序),在 DOM 層級達到一定數量後,Taro 會使用原生自定義組件協助遞歸。
簡單理解就是 DOM 結構超過 N 層後,會使用原生自定義組件進行渲染。N 默認是 16 層,可以通過修改配置項 修改 N。
H5
再查看下H5中webpackChain的作用
首先跟小程序配置類似,先調用multiPlatformPlugin這個方法的作用是為 Taro 項目配置 Webpack 的解析插件,限制只解析以 '@hb/' 開頭的模塊路徑,以支持 Taro 項目的多平台打包需求。
然後chain.module.rules.get('script').exclude.clear().add([...]);:這一段代碼涉及到對 Webpack 規則的修改
- chain.module.rules.get('script') 表示獲取名為 'script' 的規則
- exclude.clear() 清空原有的排除規則
- add([...]) 添加新的排除規則,其中傳入的函數用於判斷是否應該排除某個文件
這個規則的目的是排除一些特定的文件,包括 @tarojs/components 目錄下的文件,以滿足一定條件的 node_modules 下的文件,但不包括包含 taro 和 @hb/ 的文件。為了定製 Taro 在 H5 平台的構建規則。
然後調用hitchFeCompontsImportPlugin。
總結
總的來説在編譯方面,mini-runner 支持多端開發,使開發者能夠通過一套代碼適配不同的小程序平台。還提供了默認的構建配置,包括 loader、plugin、resolve 規則等,以滿足 Taro 框架的開發需求,並允許開發者通過配置文件或插件進行對構建過程的定製和擴展。
在對webpack配置方面,mini-runner 提供了webpackChain方法,使得開發者可以在 Webpack 配置中進行鏈式調用,方便自定義和增強配置。封裝了一套默認的 Webpack 配置,以適應 Taro 框架的特性和小程序平台的要求。此外,mini-runner 控制構建過程,提供一些配置項,例如是否監聽文件變化、是否啓用 source map 等。
附錄 - (mini-runner 部分源碼解析)
目錄結構
主流程(index)
主要分為兩個流程,根據項目配置生產webpack的構建配置,利用webpack進行代碼編譯。
基礎配置
進入 buildConf 函數,由代碼可知,首先調用了 getBaseConf ,進入該函數查看配置。
查看該配置,主要是Taro 構建過程中一部分 webpack 配置的初始化工作(包括文件擴展名、模塊解析路徑、別名等)。通過配置解析選項和引入 MultiPlatformPlugin 插件,支持跨平台文件。
- 源文件使用的擴展名,這裏包括 '.js', '.jsx', '.ts', '.tsx', '.mjs', '.vue'
- 指定導入模塊時使用 package.json 中的哪個字段,這裏的配置將優先使用 browser 屬性解析文件,其次是 module,最後是 main
- symlink
- 告訴 webpack 解析模塊時應該搜索的目錄,這裏對應的就是 node_modules 目錄
- 解析 webpack loader 包,指定 node_modules 目錄
- 代碼包是包含副作用的,不希望被 tree shaking 優化
- 配置node環境,在構建過程中對 fs(文件系統模塊)和 path(路徑模塊)的引用替換為一個空對象,從而在瀏覽器環境中模擬文件系統和路徑操作,在瀏覽器環境中,一些 Node.js 特定的模塊是不可用的,因此需要通過這種方式進行處理
- 添加MultiPlatformPlugin 插件,支持跨平台文件
自定義配置
查看 buildConf 的其餘配置,這段代碼主要負責初始化和配置一些構建過程中所需的插件、常量和選項,確保構建過程中能夠根據配置進行適當的處理和優化
- 如果是構建插件(isBuildPlugin 為真),就會處理複製文件的邏輯。如果存在 copy 對象,則將其現有的 patterns 屬性提取出來,如果不存在,則創建一個空數組。隨後,將插件相關的文件夾路徑加入這個數組。最後,使用 Object.assign 將更新後的 patterns 放回到 copy 對象中。這樣,如果之前已經有一些複製規則,現在就添加了插件相關的複製規則
- 配置插件,將 copy 屬性解析為 copy-webpack-plugin 插件,加入到 webpack 中
- 設置環境變量
- 預備構建過程中所需的常量和入口文件的配置。首先,通過 getRuntimeConstants(runtime) 獲取運行時常量,其中可能包含運行時所需的配置或環境常量。接着,通過 mergeOption([processEnvOption(env), defineConstants, runtimeConstants]) 合併來自不同來源的常量選項,包括從環境變量提取的配置、預定義的常量以及之前獲取的運行時常量。最後,通過 getEntry({ sourceDir, entry, isBuildPlugin }) 獲取項目的入口文件配置,其中包括源代碼目錄、入口文件的配置以及構建是否為插件
- 配置共享的代碼塊(Common Chunks)以用於構建。首先,根據是否構建插件來設置默認的共享代碼塊列表 defaultCommonChunks,其中包括了運行時、第三方庫、Taro 框架和通用代碼塊。接着,通過一系列條件語句,允許用户自定義共享代碼塊的配置。如果 commonChunks 是一個函數,則調用它,將默認的共享代碼塊傳遞給它,允許用户根據需要修改或替換默認的配置。如果 commonChunks 是一個非空數組,則將其用作自定義的共享代碼塊配置。最後,通過調用 getDefinePlugin([constantsReplaceList]) 獲取定義插件的配置,其中包括了前面整理好的常量替換列表。有利於靈活地配置和生成最終的共享代碼塊配置,以便在構建過程中進行優化
- 判斷是否開啓了主包優化,如果開啓了就配置相應的分割插件
Taro 構建過程中 webpack 配置的核心部分,通過鏈式調用 webpack-chain 庫的方法逐步配置了 webpack 的各項參數,包括模式、入口、出口、目標、解析規則、插件、優化等
- mode:提供 mode 配置選項,告知 webpack 使用相應模式的內置優化。
- devtool:控制是否生成 source-map。
- entry:入口文件,也就是 app.js。
- output:定義代碼編譯後的生產目錄。
- target:指定目標(target)環境。
- resolve:合併 alias 別名選項。
- module:配置 module,這裏主要是配置一些不同的 loader。
- plugin:配置 plugin 插件。
- optimization:手動配置了一些編譯選項優化。
webpack 代碼編譯
webpack 的編譯過程,支持 watch 模式,並提供了一些回調函數用於處理編譯結果。
(本文作者:劉健)