Taro跨端开发之让Taro UI支持React Native

Taro UI 不支持RN的窘境

Taro UI 文档上很早就说明会有可能支持rn了,但是快一年多了,因为taro ui团队人力的问题一直没有兼容到rn.

业务紧迫,我们等不到那一天了.自己动手丰衣足食.

Taro 传统组件打包在RN上的问题

一般来说,组件库打完包之后 dist/index.js文件会是这样的.

根据运行时的环境变量区分是否要引入哪一个组件库.

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,他会提前把所有端的代码全部预执行一遍.

代码还没有真正运行,就因为其他端的代码不兼容,直接报错了. 所以这样硬核的引入方法是不可行的.

rn组件库代码与其他端代码完全隔离

ui.js文件的改动

在src下边有一个ui.js文件,大致内容是这样的:

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.js

内容与作用跟ui.js基本上一致,唯一的区别在于, 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

组件库打包与发布

小程序与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包了.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335