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

原文链接:juejin.im

上一篇:尝鲜vue3.0-tyepscript开发组件(3)
下一篇:Flutter——另类设计,提升页面开发效率,简化跳转以及传值

相关推荐

  • 高频数据交换下Flutter与ReactNative的对比

    (标题图片来自网络,侵删) 后端使用go写的socketio服务模拟期货行情数据,每10ms推送10条行情数据 ReactNative已经尽力优化了。 Flutter由于没flutter-socket...

    2 年前
  • 随着nativescript Appium测试应用程序

    Zakaria Acharkiuser70192提出了一个问题:Testing NativeScript app with Appium,或许与您遇到的问题类似。 回答者nullpointer给出了该...

    2 年前
  • 重磅!首个多端 UI 组件库 - Taro UI 发布!

    前言 Taro 是由京东·凹凸实验室倾力打造的多端开发解决方案,旨在让一套代码在多端运行。Taro 1.0 版本发布后,也开始支持引用第三方的小程序组件库,如 iView、vant-weapp、ec...

    2 年前
  • 跨应用进程通信 - NativeMessage

    有问题,上知乎。知乎作为中文互联网最大的知识分享平台,以「知识连接一切」为愿景,致力于构建一个人人都可以便捷接入的知识分享网络,让人们便捷地与世界分享知识、经验和见解,发现更大的世界。

    2 年前
  • 试用React语法的多端框架Taro问题汇总

    Taro 是由京东 - 凹凸实验室打造的一套遵循 React 语法规范的多端统一开发框架。 我试用了有15天左右,总的来说,这是一款优秀的框架,尤其补充了目前市面上无法用 React 开发小程序的...

    2 年前
  • 解决react native ListView.DataSource 改变数组项属性视图不刷新

    当我们使用react native的ListView.DataSource来提供高性能的数据处理和访问。可是当我们改变已存在数组项的属性时,会发现视图并不会如你希望的那样更新,类似代码如下 expor...

    3 年前
  • 综合能力:如何编写脚本让 ReactNative 自动启动 Android 模拟器

    这篇文章记录笔者在 ReactNative 开发中遇到的一个具体的小问题,过程中新学到一些技巧,记录下来方便自己回顾也希望能帮助有同样需求的开发者。 跟 ReactNative 其实关系也不大,主要...

    4 个月前
  • 纯react-native ios打包发布

    react-native 发布打包 第一步: 导出js bundle包和图片资源 1.创建release_ios目录 mkdir release_ios 2.在React Native项目的根目录...

    1 年前
  • 第39期 为什么你的网页需要 CSP & Web端如何低成本打造Native体验 & 作用域与闭包-最简解释器实现

    一张图概括淘宝直播背后的前端技术 2020年,直播带货火爆全网。想一探淘宝直播背后的前端技术?本文将带你进入淘宝直播前端技术的世界。 对于大多数前端工程师来说,音视频技术是一个比较少涉足的领域,本文涵...

    4 个月前
  • 皇帝的新装-React-Native

    先看看React-native的介绍。 React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原...

    2 年前

官方社区

扫码加入 JavaScript 社区