【Taro】1246- Taro 3 與原生小程序混合開發(fā)實踐
前言—
最近接到一個項目需求,是要做出一套頁面,不僅應(yīng)用在小程序的環(huán)境中,也要應(yīng)用在 H5 里面,并同時兼容兩端原有的邏輯不變。最終經(jīng)過我們的調(diào)研梳理,決定使用當(dāng)前最新版本的 Taro 3,來實現(xiàn)多端統(tǒng)一開發(fā)的訴求。

那這里我們?yōu)槭裁催x擇 Taro 呢,我認(rèn)為有以下幾點好處
京東凹凸實驗室開發(fā), 框架穩(wěn)定性較高與 Taro 1、2 相比,Taro 3 開發(fā)體驗幸福度更高,與使用 React 或者 Vue 開 web 體驗無差 相比 UniApp 框架,Taro 靈活度高、可配置性強,可選用的開發(fā)框架也更多Taro 社區(qū)活躍度較高、周邊物料庫豐富
項目痛點—
1.通過 Taro3 進(jìn)行多端開發(fā),代碼怎樣做到兼容,可以適配到 H5 和小程序,并保證在多端順利啟動。
2.由于原生小程序端有一套自己的代碼邏輯,H5 端有一套自己的代碼邏輯,并且兩端邏輯毫不相關(guān)。怎樣做到一套代碼開發(fā)出來的頁面,同時插入 H5 或者小程序中,可以順利兼容到兩端的原有邏輯流程。
3.打造一套通用框架,可以快速高效的接入其他多端頁面,實現(xiàn)降本提效。
Taro架構(gòu)的演變—
在動手開發(fā)前,我覺得還是非常有必要先了解下 Taro 的架構(gòu)演進(jìn)的心路歷程。做到一個基本的了解。
Taro 1/2(重編譯)
在 Taro 1 與 Taro 2 階段,編譯階段起到了重要的部分。簡單來講,主要是將 Taro 代碼通過代碼編譯,轉(zhuǎn)換為各個端(各類小程序、RN、H5 等)可以運行的代碼。再通過輕量的運行時進(jìn)行適配,用 Taro 的組件庫、運行時的框架以及 API 進(jìn)行差異磨平,來解決多端差異性。

Taro3(重運行)
這一次的架構(gòu)全新升級,可以理解為重新站在瀏覽器的角度來思考前端的本質(zhì):無論開發(fā)用的是什么框架,React ,Vue 也好,jQuery 也罷,最終代碼經(jīng)過運行之后都是調(diào)用了瀏覽器的那幾個 BOM/DOM 的 API ,如:createElement、appendChild、removeChild 等,那么在小程序端我們也可以模擬實現(xiàn) DOM、BOM API 來讓前端框架直接運行在小程序環(huán)境中。
那么對于生命周期、組件庫、API、路由等差異,我們依然可以通過定義統(tǒng)一標(biāo)準(zhǔn)(如標(biāo)準(zhǔn)組件庫、標(biāo)準(zhǔn) API 等),各端負(fù)責(zé)各自實現(xiàn)的方式來進(jìn)行抹平。

Taro v3.1 開放式架構(gòu)
Taro 核心維護(hù)的平臺只有 6 個(微信、支付寶、百度、頭條、QQ、京東小程序),那么常常會有用戶對于其他平臺也需要進(jìn)行及時的支持和維護(hù)。因為對于單一平臺的兼容性代碼,涉及編譯和運行時的部分,改動起來復(fù)雜度高,且社區(qū)難以參與貢獻(xiàn)。于是便打造了一個開放式的框架,通過插件的形式擴(kuò)展 Taro 的端平臺支持能力:
插件開發(fā)者無需修改 Taro 核心庫代碼,即可編寫出一個端平臺插件。 插件使用者只需安裝、配置端平臺插件,即可把代碼編譯到指定平臺。 開發(fā)者可以繼承現(xiàn)有的端平臺插件,然后對平臺的適配邏輯進(jìn)行自定義。
那么基于此,Taro 也是根據(jù)開放式架構(gòu),進(jìn)行了調(diào)整,把內(nèi)置支持的 6 個平臺封裝成了插件,CLI 默認(rèn)會全部加載這些插件。封裝的過程中,也是檢索了各小程序最新的組件、API,并進(jìn)行更新與支持,對齊各小程序最新的能力。
項目開發(fā)搭建過程—
架構(gòu)的演變簡單了解了下,下面讓我們開始項目開發(fā)搭建~

1.Taro3 項目安裝
CLI 工具安裝
yarn?global?add?@tarojs/cli
項目初始化

2.原生小程序和 Taro 的目錄對比
首先我們先對比下兩者目錄結(jié)構(gòu)的差異,其實兩者結(jié)構(gòu)并沒有太大的不同,也很容易看懂和上手。

3.H5和小程序的打包運行分析
1)scripts 腳本配置
我們先看一下項目初始化后的 scripts 腳本:

使用 Taro 的 build 命令可以把 Taro 代碼編譯成不同端的代碼:
Taro 編譯分為 dev 和 build 模式:
dev 模式(增加 --watch 參數(shù)) 將會監(jiān)聽文件修改。 build 模式(去掉 --watch 參數(shù)) 將不會監(jiān)聽文件修改,并會對代碼進(jìn)行壓縮打包。 dev 模式生成的文件較大,設(shè)置環(huán)境變量 NODE_ENV為production可以開啟壓縮,方便預(yù)覽,但編譯速度會下降。
"build:weapp":?"taro?build?--type?weapp",?//?微信小程序
"build:swan":?"taro?build?--type?swan",??//?百度小程序
"build:alipay":?"taro?build?--type?alipay",?//?支付寶小程序
"build:tt":?"taro?build?--type?tt",?//?字節(jié)跳動小程序
"build:h5":?"taro?build?--type?h5",?//?H5
"build:rn":?"taro?build?--type?rn",?//?React?Native
"build:qq":?"taro?build?--type?qq",?//?qq小程序
"build:jd":?"taro?build?--type?jd",?//?京東小程序
"build:quickapp":?"taro?build?--type?quickapp",?//?快應(yīng)用端
2)如何支持編譯其他小程序呢
前面也講過,Taro 為了支持編譯其他端的小程序更加的方便,進(jìn)行了架構(gòu)調(diào)整為開放式架構(gòu),并通過插件的形式擴(kuò)展 Taro 的端平臺支持能力,這里以企業(yè)微信小程序舉例:
安裝插件
yarn?add?@tarojs/plugin-platform-weapp-qy
配置插件
//?config/index.js
config?=?{
??//?...
??plugins:?[
????"@tarojs/plugin-platform-weapp-qy"
??]
}
打包編譯
npm?run?build:qywx
注意:
Taro v3.1 + 開始支持
3)小程序 Taro 打出來的包怎么進(jìn)行預(yù)覽呢
h5 打包預(yù)覽和我們平常的方式?jīng)]有任何區(qū)別,那么小程序又該如何操作呢?這里以微信小程序舉例:

這個時候下載并打開微信開發(fā)者工具,然后導(dǎo)入項目根目錄的 dist 包即可,即可看到界面:

4.Taro 3 開發(fā)過程中一些細(xì)節(jié)點
這里還是推薦大家先將官方文檔簡單梳理一遍,了解下 Taro 的一些官方 api,組件庫的使用,這里就不再一一列舉。下面筆者會直接講一些開發(fā)過程中的遇到的一些踩坑點和我覺得比較重要的部分,避免大家走一些彎路。
1)使用路由
在 Taro3 中使用的路由的方式,與之前的版本會有所不同,無論是獲取項目傳入?yún)?shù)還是頁面入?yún)ⅲ际峭ㄟ^ getCurrentInstance().router 來獲取的,具體使用如下。
import?Taro,?{?getCurrentInstance?}?from?"@tarojs/taro"
import?React,?{?Component?}?from?"react"
export?default?class?Index?extends?Component?{
??componentDidMount?()?{
????console.log(getCurrentInstance().router.params)
??}
}
2)打包新增版本號
在h5編譯打包的時候,如果想要增加版本號,就需要在 config 目錄下 prod.js 文件進(jìn)行配置,這里會暴露一個專屬于 H5 的配置供大家使用。這里以設(shè)置輸出解析文件的目錄和拓展 Webpack 的 output 選項舉例:
var?config?=?require("../package.json")
var?path?=?require("path")
module.exports?=?{
??env:?{
????NODE_ENV:?"production"
??},
??defineConstants:?{
??},
??mini:?{},
??h5:?{
????publicPath:config.publicPath+config.version,
????output:?{
??????path:?path.resolve(__dirname,?`../dist/${config.version}`),?
????},
????/**
?????*?如果h5端編譯后體積過大,可以使用 webpack-bundle-analyzer 插件對打包體積進(jìn)行分析。
?????*?參考代碼如下:
?????*?webpackChain?(chain)?{
?????*???chain.plugin('analyzer')
?????*?????.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin,?[])
?????*?}
?????*/
??}
}
3)接口請求
對于網(wǎng)絡(luò)請求,Taro 封裝了一套自己的 API,比如說我這邊用的是 async/await 用法:
const?options?=?{
??method:?requestType,?//?"GET"或者"POST"
??url,
??data:?param,
??credentials:?"include"?as?credentialsType,
??timeout:?1000?*?30,
??header:?h,
};
const?res?=?await?Taro.request(options)
注意:
小程序的環(huán)境下,接口 url 的請求一定是 https
項目難點攻克—
對于這次需求來說,最需要做的事情,就是如何借助 Taro3 開發(fā)一套頁面,同時去兼容兩端(微信小程序端和 H5 端)的流程。并且將微信小程序環(huán)境下打包出來的 dist 目錄,插入到原生的小程序中,實現(xiàn)混合開發(fā)。
1.兼容兩端流程搭建
這里我們首先需要封裝函數(shù)來區(qū)分不同環(huán)境,封裝在 utils 目錄中。
const?Utils?=?{
??isH5()?{
????return?process.env.TARO_ENV?===?"h5"
??},
??isWeapp()?{
??return?process.env.TARO_ENV?===?"weapp"
?},
}
export?default?Utils
這樣我們在開發(fā)過程中,比如點擊提交按鈕,區(qū)分出是 h5 環(huán)境下,便處理 h5 的邏輯。區(qū)分出是微信小程序的邏輯,便處理微信小程序的邏輯。
2.混合開發(fā)
現(xiàn)在我們面臨這樣一個場景,就是在此 Taro 項目框架,區(qū)分出是微信小程序的環(huán)境下了,現(xiàn)在我們需要跳轉(zhuǎn)到原生小程序的某個頁面,比如說喚起原生的登陸打通,那么我們又該如何實現(xiàn)呢?
讓我們思考下,即使只開發(fā)了一個頁面,小程序打出的包 dist,也是一整個小程序。那我們現(xiàn)在想要將打出的包插入到原生小程序中去實現(xiàn),那么我們需要打包成一個單獨的分包。
1)以混合模式進(jìn)行打包
非常幸運的一點是,Taro 3 官方提供了混合開發(fā)的功能,可以讓原生小程序項目和打包出來的項目進(jìn)行混合開發(fā)使用,通過 --blended 命令。
taro?build?--type?weapp?--blended
這個時候,在打包出來的 app.js 中會暴露出 taroApp,供我們在原生小程序的 app.js 頁面下去調(diào)用其生命周期。

但是存在這樣一個問題,在執(zhí)行我們的原生小程序項目時,我們通過引用在原生項目下的 app.js 里引入 Taro 項目的入口文件,來提前初始化一些運行時的邏輯,因此要保證 Taro 項目下的 app.js 文件里的邏輯能優(yōu)先執(zhí)行。所以說只是 --blended 命令這種,只適合主包的頁面,分包的話,沒法優(yōu)先執(zhí)行。
2)解決分包開發(fā),引入 @tarojs/plugin-indie 插件
先進(jìn)行安裝
yarn?add?--dev?@tarojs/plugin-indie
然后引入插件配置
//?config/index.js
const?config?=?{
??//?...
??plugins:?[
????"@tarojs/plugin-indie"
??]?
??//?...
}
簡單來說,就是在編譯代碼時,對頁面下的 js chunk 文件進(jìn)行 require 引入的目錄調(diào)整,增加對應(yīng)的 module 的 sourceMap 映射。這樣在訪問到我們 Taro 下的分包頁面時,就可以做到優(yōu)先執(zhí)行了。
3)手寫 @tarojs/plugin-mv 插件,自動化挪動打包后的文件
在處理好分包的打包流程后,我們在原生小程序的 pages 頁面下建立一個頁面文件夾 taroMini,為了導(dǎo)入我們 Taro 項目下打包出的分包頁面。然后在原生小程序的 app.json 中,引入分包的路徑配置。
{
??"subPackages":?[
????{
??????"root":?"pages/taroMini/pages/riskControlAnswer",
??????"pages":?[
????????"index"
??????]
????}
??]
}
現(xiàn)在就是我們手動把 Taro 打包出來的文件夾,拖動到原生小程序的 taroMini 目錄下就可以運行我們的頁面了。如圖:

這個時候,我們又要思考下了,每次打包出來的 dist 文件夾,都要手動拖入到原生小程序的項目中么,有沒有一種自動化的方式,讓其自己挪動呢。這里我們就要開始手寫一個插件了:
//?plugin/index.js
const?fs?=?require("fs-extra")
const?path?=?require("path")
export?default?(ctx,?options)?=>?{
??ctx.onBuildFinish(()?=>?{
????const?blended?=?ctx.runOpts.blended?||?ctx.runOpts.options.blended
????
????if?(!blended)?return
????console.log("編譯結(jié)束!")
????const?rootPath?=?path.resolve(__dirname,?"../..")
????const?miniappPath?=?path.join(rootPath,?"jdc_wx_ecard")
????const?outputPath?=?path.resolve(__dirname,?"../dist")
????//?taroMini是你在京東有禮小程序項目下的路由文件夾
????const?destPath?=?path.join(miniappPath,?`./pages/taroMini`)
????console.log("outputPath",?outputPath)
????console.log("destPath",?destPath)
????if?(fs.existsSync(destPath))?{
??????fs.removeSync(destPath)
????}
????fs.copySync(outputPath,?destPath)
????console.log("拷貝結(jié)束!")
??})
}
其實代碼仔細(xì)看一下,實現(xiàn)思想就是進(jìn)行一個文件夾的自動挪動腳本。然后我們把我們手寫好的這個插件,引入到我們的 Taro 項目中
//?config/index.js
const?config?=?{
??//?...
??plugins:?[
????"@tarojs/plugin-indie",
????path.join(process.cwd(),?"/plugin/index.js")
??]?
??//?...
}
4)應(yīng)用
那么上面所提到的,在 Taro 項目中跳轉(zhuǎn)到原生小程序的某個頁面中,就可以在我們的本地 Taro 項目中(區(qū)分好是微信小程序的環(huán)境下)正常書寫了。
const?{?orderId?}?=?param
const?fromPageType?=?""
const?returnPage?=?encodeURIComponent(`/pages/taroMini/pages/riskControlAnswer/index?orderId=${orderId}`)
const?url?=?`/pages/login/index/index?returnPage=${returnPage}&pageType=${fromPageType}&noWXinfo=1`
Taro.redirectTo({?url?})
其他調(diào)用原生小程序的功能也可以正常開發(fā)了。
項目總結(jié)—
這樣我們就實現(xiàn)了最開始我們提到的一些需求點,實現(xiàn)了原生小程序和 Taro 項目的混合開發(fā),也實現(xiàn)了 Taro 項目端和原生小程序端兩個項目之間的自動化打通。其實對于 Taro 3 進(jìn)行深挖,還有很多可以值得探索梳理的地方,后續(xù)有機會再和大家分享下~
參考資料—
Taro 官方文檔:?https://nervjs.github.io/taro/docs/ 凹凸實驗室-掘金首頁:?https://juejin.cn/team/6930527975943176199 京東購物小程序 | Taro3 項目分包實踐 GMTC | 《小程序跨框架開發(fā)的探索與實踐》演講全文

回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~
點擊“閱讀原文”查看 130+ 篇原創(chuàng)文章
