Taro UI does not support RN’s dilemma

Taro UI documentation has long stated that it is possible to support RN, but it has been more than a year since the Taro UI team has not been compatible with RN due to manpower issues.

Business is pressing and we can’t wait for that day. Do it yourself.

Taro traditional component packaging issues on RN

In general, the dist/index.js file will look like this after the component library is packaged.

Depending on the environment variables at run time, which component library to introduce or not.

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
    }
Copy the code

Ideally, an RN component library could be introduced by adding an RN environmental judgment.

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') {
      // Ideal mode, just need to add this paragraph
      module.exports = require('./rn/ui')
      module.exports.default = module.exports
    } else {
      module.exports = require('./weapp/ui')
      module.exports.default = module.exports
    }
Copy the code

Rn, however, will pre-execute all of the code on all sides of the component library if it introduces an index file called dist/index.js.

The code is not actually running, because the other side of the code is not compatible, directly reported an error. So this hardcore approach to introduction is not feasible.

Rn component library code is completely isolated from other side code

Changes to the ui.js file

Under SRC there is a ui.js file that looks like this:

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'

// Other components...

Copy the code

In order to make rn compatible with the original component library, taro can be used to distinguish the end of a file based on the suffix. You need to create a new uI.rn.js

The content and function are basically the same as ui.js, the only difference is that the path from, some components after the page need to add rn suffix.

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'  // For RN-compatible components
export { default as AButton } from './components/button/index'  // All compatible components

Copy the code

Changes to component library index files

Normally,rn is packaged to create an RN_temp folder that contains pure RN code. This code doesn’t have to be generated to the dist directory like the others.

My component library index file (packes. json) main points to an RN component library specific index file.

Rn’s component library index file I’ll call main.rn.js:

"use strict";
module.exports = require('./rn_temp/ui.rn.js');
module.exports.default = module.exports
Copy the code

The other end points to the dist directory and h5 and various applets

"use strict";
module.exports = require('./dist/index');
module.exports.default = module.exports
Copy the code

Component library packaging and publishing

Applets and h5-side component libraries are still packaged and distributed in the same way. However, on the Rn side, you need to modify the package.json content at the time of publication.

Here’s a simple release script:

const { execSync } = require('child_process');
const fse = require('fs-extra');
const path = require('path');

// Update the version number
execSync("npm version patch");
const pkgPath = path.relative(process.cwd(),'package.json')
var packageData = fse.readJsonSync(pkgPath);
// h5 applets component library

console.log("Start building the applets component library")
packageData.name = 'taro-ui'
packageData.main = 'main.js'
fse.outputJsonSync(pkgPath, packageData,{spaces:2});
execSync(`npm run build:component && crgt publish; `);


// Change the NPM package name and re-publish a package
console.log("Start building the RN component library.")
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; ');

// Restore the name
packageData.name = 'taro-ui'
packageData.main = 'main.js'
fse.outputJsonSync(pkgPath, packageData,{spaces:2});
execSync('git push');

Copy the code

Here you can see that when I released the component library, I released two NPM packages.

As an OCD, don’t take it too seriously. Because many of Taro’s dependencies do the same.

How do you use such a component library

In business development, code should be introduced directly into the TARo-UI NPM package.

But what about rn?

Here we learn from taro’s approach to official dependencies by replacing the package name taro-UI-RN with the package name taro-UI-RN at compile time.

So we need to simply modify taro’s source code. The 1.3.X version we used, if it is a higher version, should be able to be modified in other ways.

In 1.3.x, we need to change the tarojs/ CLI code.

The RN module in the CLI has a transformJS file. Search source.value = PACKAGES[‘@tarojs/ component-rn ‘] in this file to find the location of this line of code.

This code is basically saying, when you’re walking through the AST, if you’re introducing a package named @tarojs/components replace it with @tarojs/components-rn.

So let’s do the same logic, else if

else if (value === PACKAGES['@tarojs/components']) {
    source.value = PACKAGES['@tarojs/components-rn']
// Add the next judgment
}else if (value === 'taro-ui') {
  source.value = 'taro-ui-rn'
}
Copy the code

This way, we can introduce the correct NPM package under normal development conditions.