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

相关文章
相关标签/搜索