Taro跨端開發之讓Taro UI支持React Native

Taro UI 不支持RN的窘境

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

業務緊迫,咱們等不到那一天了.本身動手豐衣足食.git

Taro 傳統組件打包在RN上的問題

通常來講,組件庫打完包以後 dist/index.js文件會是這樣的.npm

根據運行時的環境變量區分是否要引入哪個組件庫.json

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的環境判斷,就能夠作到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
    }
複製代碼

但是現實不是這樣的,rn若是引入組件庫的索引文件,是dist/index.js,他會提早把全部端的代碼所有預執行一遍.markdown

代碼尚未真正運行,就由於其餘端的代碼不兼容,直接報錯了. 因此這樣硬核的引入方法是不可行的.app

rn組件庫代碼與其餘端代碼徹底隔離

ui.js文件的改動

在src下邊有一個ui.js文件,大體內容是這樣的:ui

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能夠根據文件後綴名區分端的特性就排上用場了. 須要新建一個ui.rn.jsspa

內容與做用跟ui.js基本上一致,惟一的區別在於, from 的路徑,有的組件後面頁須要加上rn後綴.code

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
複製代碼

組件庫打包與發佈

小程序與h5端的組件庫仍是按照原來的打包與發佈模式. 可是rn端的話,須要在發佈的時候修改一下package.json內容.

我這裏提供一個簡單的發佈腳本:

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包名,從新發佈一個包
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');

複製代碼

在這裏你應該發現了,我發佈組件庫的時候,是發佈兩個npm包.

做爲強迫症的你,不要太在乎這些. 由於taro不少的依賴也是這樣乾的.

如何使用這樣的組件庫

在業務開發的時候,代碼只要直接引入 taro-ui這個npm包就行了,

可是若是是rn業務該怎麼辦呢?

這裏咱們借鑑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'
}
複製代碼

這樣,咱們就能夠正常開發的狀況下引入正確的npm包了.

相關文章
相關標籤/搜索