Taro is a multipurpose solution that follows the React syntax specification. Compile the source code into running codes of different terminals (wechat, JINGdong, Baidu, Alipay, Bytedance applet, Kuaiapp, H5, React-Native, etc.) by using the Taro compilation tool.

Write Once, Run Anywhere, has been loud and clear since I started writing JQuery. Back then, IT was just a matter of dealing with JS compatibility in different browsers. Now Jq hero is late, led by ng, Vue and React three spirit of the front-end framework began to develop rapidly, is no longer satisfied with the front-end browser this mu three.

But don’t be so quick to wander, although the ideal is beautiful, the reality is very cruel. As the development went further, I found many cross-platform pit points, so I sorted them out, and this article came into being.

Style compatibility issues in multiple endpoints

Of all the styles, H5 is the most compatible, followed by applets, and RN is the worst. Unified multiterminal is to align the short board, that is, to manage styles with RN constraints, while taking into account the limitations of small programs, the core can be summarized in three points:

  • useFlexlayout
  • Based on theBEMWriting style
  • usingstyleOverrides the style of the component

One thing to notice here in Flex is that the View tag in RN, by default, has a main axis of column. The approach we took in our project was to explicitly declare the main axis whenever flex layout was useful. The reason why we don’t just call the View tag display: flex; Flex-direction: column, because some of the built-in component styles on H5 may be out of order.

BEM BEM stands for block, Element, or modifier, using different blocks, functions, and styles to name elements. The BEM naming convention can effectively solve the problem of global style pollution in React, and let people know the relationship and function of each module just by looking at the class name.

Styles in taro compile RN side, the processing of style files can be divided into the following steps:


The CSS to StyleSheet in the figure above uses CSS-to-react-native – Transformbabel-plugin-transform-JsX-to-stylesheet, Convert Scss/Less/Css files to React Native StyleSheet files and replace the className(including complex expressions such as trinary operators and classnames()) directly with style in JSX syntax.

These are some of the operations Taro does for us when compiling RN. Taro also provides conditional compilation for handling differential styles.

Conditional compilation of style files

If both index.scss and index.rn. SCSS style files exist in the directory, simply write import ‘./index.scss’ to reference the style file in the js file. In RN, index.rn. SCSS is automatically introduced, while other platforms introduce index.scss to achieve conditional compilation of style files on RN and non-RN platforms.

Conditional compilation of style code

Reserved for specified platform:

/* #ifdef %PLATFORM% */ * #endif */Copy the code

Specified platform culling:

/* #ifndef %PLATFORM% */ #endif */Copy the code

%PLATFORM% indicates the PLATFORM type that is currently being compiled, which is the same as process.env.TARO_ENV (appellate/swan/alipay/h5 / rn/tt/QQ/quickapp).

If multiple platforms are used, separate them with Spaces

Ex. :

.wrap{
    background: red;
    /* #ifdef weapp h5 */
    background: green;
    /* #endif */
} Copy the code

Cross-platform development

Taro contains a variable named taro.env. TARO_ENV to evaluate the current compilation type, including appellate/swan/ALIPAY/h5 / rn/tt/QQ/quickApp. These variables can be used to realize the code in different environments, and during compilation, the code that does not belong to the current compilation type will be removed, only the code under the current compilation type will be retained, for example, want to reference different resources in wechat applet and H5 side respectively:

if (process.env.TARO_ENV === 'weapp') {
  require('path/to/weapp/name')
} else if (process.env.TARO_ENV === 'h5') {
  require('path/to/h5/name')
}
Copy the code

It can also be used in JSX to determine which components to load on different ends

render () {
  return (
    <View>
      {process.env.TARO_ENV === 'weapp' && <ScrollViewWeapp />}
 {process.env.TARO_ENV === 'h5' && <ScrollViewH5 />}  </View>  ) } Copy the code

These built-in variables are great, but they can be very difficult to maintain if your code is filled with a lot of logical statements. Taro’s team has also taken these considerations into consideration. If a component has multiple differences, it is entirely possible to use the corresponding platform naming format of the component. For example, if the Test component needs to have three different versions of wechat mini program, Baidu mini program and H5, the script file can be organized as follows

The test.js file, the default form of the test component, can be compiled into the test.h5.js file used by wechat applet, Baidu applet and other ends other than H5. The app.js file is the H5 version of Test. App.swan. js file is the Baidu applet version of Test

Four files, external exposure is a unified interface, they accept the same parameters, but internal code implementation for their respective platforms.

When using the Test component, the reference method is still the same as before. Directly import the filename without the end type. Taro will automatically recognize and add the end type suffix when compiling

// import Test from '@/components/test.h5'
import Test from '@/components/test'
Copy the code

There are no cookies in the applet

If cookies are used to save login status in a project, the applet should be more compatible. It’s not complicated, it’s just adding a cookie field to the header of the request, that’s all.

import Taro from '@tarojs/taro';

// Saved cookies
let cookies = Taro.getStorageSync('cookies') | |' ';
// Applet environment
constisMP = Taro.getEnv() ! == Taro.ENV_TYPE.WEB || Taro.getEnv() ! == Taro.ENV_TYPE.RN // A way to unify requests in a project export default const fetch = (option) = > {  const {url, data, method = 'GET', header = {}} = option;   if(method === 'POST') { header['content-type'] = 'application/json'  }  if(isMp){  header['Cookies'] = cookies;  }   return Taro.request({  url,  data,  method,  header  }) }  export function post(url, data) {  return fetch({ url, data, method: 'POST' }) }  export function get(url, data) {  return fetch({ url, data, method: 'GET' }) }  // Login interface export const login = (data) = > {  return new Promise((resolve, reject) = > {  fetch({url: '/api/login', data, method: 'POST'}).then((res) = > {  if(res.code === 200) { // Separate cookies separated by commas in the response header with semicolons and store them  cookies = res.header['Cookies'].replace(/,/g.'; ');  Taro.SetStorage('Cookie', cookies);  }  resolve(res);  }).catch((error) = > {  reject(error);  })  }) } Copy the code

Taro multiterminal development implementation

After a period of development and some understanding, I have probably understood the essence of Taro’s multi-development. Taro abstracts the syntax of your React class into a syntax tree (AST) at compile time. The AST is then analyzed and converted to generate the target syntax.


Based on the principle of compilation, Taro will smooth out the difference between each end when compiling.

Compile time

For example, when converting the applet side, the Render in Taro will remove all JSX elements from the JS file, which will be converted into WXML for the applet after a series of transformations.

For example, a common loop operation in JSX:

<View>
  {
    list.map(item= > <Text onClick={this.handleClick}>{item}</Text>)
  }
</View> Copy the code

At compile time, Taro will compile the above code into the Ast JSON format as follows:

{
    "type": "element".    "tagName": "text".    "attributes": [
        {"bindtap": "handleCLick"},
 {"wx:for": "{{list}}"},  {"wx:for-item": "item"} ]. "children": [  {"type": "text"."content": "{{item}}"}  ] } Copy the code

The callee (list) of the function is the value of the wx:for attribute, the first argument of the anonymous function is the value of wx:for-item, the second argument is wx:for-index, and the children of the Text element is a JSX expression. With such a list of data structures, it is possible to generate a WXML fragment. You can refer to the toHTML function in the Taro source – github.com/andrejewski…

Due to the ever-changing ways of writing JSX, Taro has not yet supported all the ways of writing JSX. Some commonly used Taro will be converted accordingly, while some are limited by wechat mini-programs. Taro does not yet support Taro operations that can be prevented by using ESLint warnings or reporting errors during compilation (this is why many JSX syntax did not support Taro in the early years). As the Taro team has been iterating over the years, the level of support and additions to the JSX section have progressed quite well. Details can be found in the documentation best Practices on the Taro website.

The runtime

Convert only the code syntax at compile time, including JSX’s conversion to applets XML. At the component level, the Taro team has customized a set of runtime standards to smooth out the differences between platforms. Includes standard runtime framework, standard basic component library, standard side capability API, wherein the runtime framework and API correspond to @taro/taro, component library corresponds to @tarojs/ Components, with wechat applet as the standard, to achieve these standards in different end, so as to achieve a set of code to multi-side code seamless conversion.

It also smooths out state, event binding, and lifecycle differences in conjunction with the compilation process. The native API is extended at runtime, and features such as passing parameters through bind during event binding and calling native API in the way of Promise are realized.

These are some of Taro’s efforts at compile time and run time to address multi-platform issues.


This article is formatted using MDNICE