Taro UI 不支持RN的窘境
Taro UI 文檔上很早就說明會有可能支持rn了,但是快一年多了,因為taro ui團隊人力的問題一直沒有兼容到rn.
業(yè)務(wù)緊迫,我們等不到那一天了.自己動手豐衣足食.
Taro 傳統(tǒng)組件打包在RN上的問題
一般來說,組件庫打完包之后 dist/index.js文件會是這樣的.
根據(jù)運行時的環(huán)境變量區(qū)分是否要引入哪一個組件庫.
if (process.env.TARO_ENV === 'weapp') {
module.exports = require('./weapp/ui')
module.exports.default = module.exports
} else if (process.env.TARO_ENV === 'h5') {
module.exports = require('./h5/ui')
module.exports.default = module.exports
} else {
module.exports = require('./weapp/ui')
module.exports.default = module.exports
}
理想模式下,只要加入一個rn的環(huán)境判斷,就可以做到rn組件庫的引入了.
if (process.env.TARO_ENV === 'weapp') {
module.exports = require('./weapp/ui')
module.exports.default = module.exports
} else if (process.env.TARO_ENV === 'h5') {
module.exports = require('./h5/ui')
module.exports.default = module.exports
} else if (process.env.TARO_ENV === 'rn') {
// 理想模式,只需要加這一段
module.exports = require('./rn/ui')
module.exports.default = module.exports
} else {
module.exports = require('./weapp/ui')
module.exports.default = module.exports
}
可是現(xiàn)實不是這樣的,rn如果引入組件庫的索引文件,是dist/index.js,他會提前把所有端的代碼全部預(yù)執(zhí)行一遍.
代碼還沒有真正運行,就因為其他端的代碼不兼容,直接報錯了. 所以這樣硬核的引入方法是不可行的.
rn組件庫代碼與其他端代碼完全隔離
ui.js文件的改動
在src下邊有一個ui.js文件,大致內(nèi)容是這樣的:
import Taro from '@tarojs/taro'
import './style/index.scss'
export { default as AActionSheet } from './components/action-sheet'
export { default as AActionSheetItem } from './components/action-sheet/body/item'
export { default as AText } from './components/text'
export { default as AToast } from './components/toast'
export { default as AButton } from './components/button'
// 其他組件...
為了更好的在原來組件庫上做rn的兼容,利用taro可以根據(jù)文件后綴名區(qū)分端的特性就排上用場了.
需要新建一個ui.rn.js
內(nèi)容與作用跟ui.js基本上一致,唯一的區(qū)別在于, from 的路徑,有的組件后面頁需要加上rn后綴.
import Taro from '@tarojs/taro'
import './style/index.scss'
export { default as AActionSheet } from './components/action-sheet/index.rn'
export { default as AActionSheetItem } from './components/action-sheet/body/item/index.rn'
export { default as AText } from './components/text'
export { default as AToast } from './components/toast/index.rn' // 針對rn兼容的組件
export { default as AButton } from './components/button/index' // 各端都兼容的組件
組件庫索引文件的改動
普通情況下,rn打包完之后會生成一個 rn_temp
文件夾,這里面就是純粹的rn代碼.
這里面的代碼完全不用像其他端一樣生成到dist目錄.
我的組件庫索引文件,也就是packages.json里面的main指向一個rn組件庫專屬的索引文件就可以了.
我這里命名為: main.rn.js
rn的組件庫索引文件:
"use strict";
module.exports = require('./rn_temp/ui.rn.js');
module.exports.default = module.exports
其他端的話就指向dist目錄就好了
h5與各種小程序端
"use strict";
module.exports = require('./dist/index');
module.exports.default = module.exports
組件庫打包與發(fā)布
小程序與h5端的組件庫還是按照原來的打包與發(fā)布模式.
但是rn端的話,需要在發(fā)布的時候修改一下package.json內(nèi)容.
我這里提供一個簡單的發(fā)布腳本:
const { execSync } = require('child_process');
const fse = require('fs-extra');
const path = require('path');
// 升級一下版本號
execSync("npm version patch");
const pkgPath = path.relative(process.cwd(),'package.json')
var packageData = fse.readJsonSync(pkgPath);
// h5 小程序組件庫
console.log("開始構(gòu)建小程序組件庫")
packageData.name = 'taro-ui'
packageData.main = 'main.js'
fse.outputJsonSync(pkgPath, packageData,{spaces:2});
execSync(`npm run build:component && crgt publish;`);
// 修改一下npm包名,重新發(fā)布一個包
console.log("開始構(gòu)建rn組件庫")
packageData.name = 'taro-ui-rn'
packageData.main = 'rn_temp/ui.rn.js'
fse.outputJsonSync(pkgPath, packageData,{spaces:2});
execSync('npm run build:rn && crgt publish;');
// 還原名字
packageData.name = 'taro-ui'
packageData.main = 'main.js'
fse.outputJsonSync(pkgPath, packageData,{spaces:2});
execSync('git push');
在這里你應(yīng)該發(fā)現(xiàn)了,我發(fā)布組件庫的時候,是發(fā)布兩個npm包.
作為強迫癥的你,不要太在意這些. 因為taro很多的依賴也是這樣干的.
如何使用這樣的組件庫
在業(yè)務(wù)開發(fā)的時候,代碼只要直接引入 taro-ui這個npm包就好了,
但是如果是rn業(yè)務(wù)該怎么辦呢?
這里我們借鑒taro處理官方依賴的方式,在代碼編譯時將 taro-ui
替換包名 taro-ui-rn
就可以了.
所以我們需要簡單的修改一下taro的源碼. 我們用的1.3.X版本,如果是更高的版本,應(yīng)該可以有其他方式修改.
在1.3.x的版本中,我們需要修改tarojs/cli的代碼.
在cli中的rn模塊有一個 transformJS
文件, 在這個文件搜索一下 source.value = PACKAGES['@tarojs/components-rn']
,找到這行代碼的位置.
這段代碼的意思大概就是,在遍歷ast的時候,如果引入的包名為@tarojs/components
將其替換成為 @tarojs/components-rn
.
所以我們按照一樣的邏輯,多加一行else if
else if (value === PACKAGES['@tarojs/components']) {
source.value = PACKAGES['@tarojs/components-rn']
// 加上下一段判斷
}else if (value === 'taro-ui') {
source.value = 'taro-ui-rn'
}
這樣,我們就可以正常開發(fā)的情況下引入正確的npm包了.