Taro跨端開發(fā)之讓Taro UI支持React Native

Taro UI 不支持RN的窘境

Taro UI 文檔上很早就說明會有可能支持rn了,但是快一年多了,因為taro ui團隊人力的問題一直沒有兼容到rn.

業(yè)務緊迫,我們等不到那一天了.自己動手豐衣足食.

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,他會提前把所有端的代碼全部預執(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("開始構建小程序組件庫")
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("開始構建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');

在這里你應該發(fā)現(xiàn)了,我發(fā)布組件庫的時候,是發(fā)布兩個npm包.

作為強迫癥的你,不要太在意這些. 因為taro很多的依賴也是這樣干的.

如何使用這樣的組件庫

在業(yè)務開發(fā)的時候,代碼只要直接引入 taro-ui這個npm包就好了,

但是如果是rn業(yè)務該怎么辦呢?

這里我們借鑒taro處理官方依賴的方式,在代碼編譯時將 taro-ui 替換包名 taro-ui-rn就可以了.

所以我們需要簡單的修改一下taro的源碼. 我們用的1.3.X版本,如果是更高的版本,應該可以有其他方式修改.

在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包了.

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容