As the number of applet users increases, more and more platforms begin to expand their applet capabilities. Such as the traditional micro channel small program, MY factory jingdong small program, byte and Baidu and many other platforms are joining. But the current development environment is one of “small steps, fast iterations”. Therefore, “one set of code, multi-terminal operation” has become the dream of many teams. We used Taro + Vue3 + NutUI3 in the recent Jingcaiyun mobile mall project to practice multi-terminal development.

Development Background (Project background)

Beijing mining cloud will demand management, find the source bidding, supplier management, self-service mall and collaborative performance, financial settlement “six management ability” collection at an organic whole, be able to complete the more efficient the introduction of the supplier and the whole life cycle management, and help enterprises through the analysis of the intelligent procurement will automatically match purchase requisitions and purchase plan, to achieve convenient and efficient supply chain management. At the same time, the product hopes that the project can not only run on the PC side, but also requires the development of H5 page to be easily embedded into the customer APP to meet the needs of customer service to build their own e-commerce mall. In the next stage, the project is also expected to be quickly applied in small programs.

Technical selection and introduction

Technical comparison

As soon as we received the demand, we started to investigate the existing multi-end frameworks in the market, such as Taro, UNI-App, Chameleon, etc. In order to find a more suitable framework for us, we made a comparison from the following aspects:

  1. The development tools

Uni-app should be the next best thing. It is the most well-documented and comes with the IDE Graphical development tool (HBuilderX) that compiles test releases with the click of a mouse. Other frameworks use CLI command-line tools, but it’s worth noting that Chameleon has its own syntax checking tool, and Taro has written ESLint rules and rule sets separately.

  1. Technology stack

Mpvue, Uni-App, and Taro all support TypeScript, and editor auto-completion can be achieved through typing. In addition to API completion, Taro can also complete components automatically thanks to TypeScript support for JSX. However, Taro provides complete support for React and Vue, and supports only one front-end framework for other applications.

In terms of CSS syntax, all frameworks support SCSS, LESS, Stylus, and Taro supports CSS Modules.

  1. Multiterminal support

Uni-app, Taro and Chameleon all support common applets on the market.

  1. The performance comparison

Whether Taro or UNI-app, setData optimization is the most important thing in small program performance optimization, and optimization mainly has two directions:

  • MinimizesetDataFrequency of calls
  • Minimize the number of timessetDataTransmitted data

We wrote a long list of tests by ourselves, including Taro version, UNI-App version and native applet version. The efficiency of data scrolling was similar in the first few pages, but after 7 or 8 pages, we found that uni-App was slow when loading new pages.

I guess uni-App doesn’t have a recycle mechanism in the long list, so I spent some time improving the demo. When I scroll down, I wipe out the data in the previous pages, and then I can’t feel the difference in fluency when I scroll down again.

Therefore, it is concluded that Taro is more careful in performance optimization and should pay attention to code optimization when using UNI-app.

To sum up, Taro and UNI-App are among the best multiterminal frameworks on the market. On every metric, they’re about the same. But Taro is more open and diverse to developers, with a library of NutUI components more in line with JD.com’s style. So Taro + NutUI3 is our first choice.

Let’s start with the tools we’ll be using

Taro is introduced

Taro is an open cross-end cross-framework solution that supports the use of React/Vue/Nerv frameworks to develop wechat/JD.com/Baidu/Alipay/Bytedance/QQ mini program/H5 / RN and other applications.

Taro has entered the 3.x era with a more efficient and streamlined DOM/BOM API package (Taro-Runtime) that enables simultaneous React and Vue 2/3 development.

Tarojs/Runtime is Taro’s runtime adapter core, which implements a streamlined DOM, BOM API, event system, Web framework, and applets framework bridge layer, among others

The Web framework can then render an Taro DOM tree using the Taro emulated API, but this all runs at the logic level of the appllet. The XML template for the widget needs to be written down in advance. How do Taro use a static template file to render the dynamic Taro DOM tree?

Taro has chosen to use small programs that can reference other features to render each DOM node of the Taro DOM tree one by one. In this case, we only need to setData the serialized data of the Taro DOM tree to trigger the mutual reference of data, thus rendering the final UI. More of these principles are described in detail below.

NutUI introduction

As a jingdong style lightweight mobile Vue component library, the NutUI 3 version adopts the architecture of Vite + Vue3 + TS, while fully supporting applets adaptation. Taro also officially lists NutUI as a recommended component library for the Vue technology stack.

How does NutUI support applets?

For each component, we added.taro. Vue files to the directory structure of the original component specifically to handle taro compatibility. At the time of use, you can install the regular Vue3 version or Taro version according to your requirements.

#Vue3 Project NPM i@nutui /nutui@next -s # Nutui Applets Multiterminal project NPM i@nutui /nutui@taro -sCopy the code

When used, the corresponding component can be referenced according to the different source.

import { createApp } from 'vue';
// vue
import { Button } from '@nutui/nutui';
// taro
import { Button } from '@nutui/nutui-taro';
Copy the code

Thus, we can use this component library in Taro.

The business development

In order to meet the needs of enterprise customers to build their own e-commerce mall, jingcaiyun Mall has set up a complete mall process, including home page (banner chart, navigation, recommendation and other floors), classification, search, product details, shop list, shop details, shopping cart, order, personal page, address selection, etc. At the same time, for the bulk purchase, increase the order submission and approval process. At the same time, the mall will be more enriched in the later period, to provide customers with more efficient and fast procurement services.

Get a visual feel for it

Support multi-platform embedding

In order to facilitate the introduction of app into our mall, better drainage mall goods. We only need to add our entry link in the client’s APP and use Cookie to get through the login state, then it can be perfectly embedded.

We set the domain parameter of Cookie to realize the same Cookie between different domain names.

document.cookie = "Cookie=testcookie; domain=test.com; path=/";Copy the code

Theme customization

In order to better serve various access platforms and keep the same style with the access platform, we must implement the theme configurable, and pass in different parameters according to the theme color of the access platform to achieve the consistent theme effect.

First, during development, we extracted common SCSS files containing our common theme style variables.

$primary-color: #478ef2; $bg-color-selected: #fef4f3; $bg-color-disabled: #fcd4cf; $border-color: #ececec; / / more...Copy the code

In our development process, we directly use the corresponding style variables, not only convenient for our later maintenance, but also simple to achieve the theme of a modification, global application requirements. However, we need to modify the SCSS file every time we change the theme color. We want to use an interface to return the theme color and then render the theme. How do you do that? Thanks to the function of Vue3 SFC, we can directly write CSS styles in Vue file style, we can use V-bind to bind variables, so as to realize the use of JS variables in CSS styles.

Const colorState = reactive({primaryColor: '#f0250f', // default color borderColor:# fef4F3}); Router.isready ().then(async () => {... const result = await getTheme(); // Get the topic's interface if (result? .state === 0) { colorState.primaryColor = result.primaryColor; colorState.borderColor = result.borderColor; }}); <style lang=" SCSS "> // define global class. Primary-color {color: v-bind(primaryColor); } .border-color { color: v-bind(borderColor); } </style>Copy the code

With the above definition, we can implement dynamic styling directly in our code using CSS classes such as primary-color.

Taro + NutUI application

With the official release of Vue3, better performance, smaller size, better TypeScript integration, and new apis for handling large-scale use cases, all developers are embracing Vue3.

Taro jumped on the bandwagon and quickly began to support Vue3 code conversion in Taro3, while NutUI followed suit, first completing the upgrade of all components Vue2 to Vue3, followed by the adaptation of Taro to better serve developers.

Currently, Taro only provides one way to develop: install the Taro command line tool (Taro CLI) to develop. Taro CLI can be used after installing Taro CLI by entering the command NPM i-g@tarojs /cli in terminal. There are complete courses on Taro’s official website and how to use and develop them. We will not focus on them here.

Let’s focus on how Taro and NutUI implement a set of code applications.

Let’s first look at the architecture of the applets. Wechat applets are mainly divided into logical layer and view layer, and the native part below them. The logic layer is mainly responsible for JS running, and the view layer is mainly responsible for page rendering. They mainly communicate with each other through Events and Data, and call the native API through JSBridge. This is also the architecture of most small programs led by wechat small program.

The native part of the applet is different from platform to platform, and this part is a black box for front-end development. So the front-end layer only needs to focus on the logical layer and the view layer.

Therefore, you only need to call the corresponding App()/Page() methods in the logic layer, and process data in the method, provide life cycle/event functions, etc., and provide the corresponding templates and styles in the view layer for rendering to run the applet. This is what most applets development frameworks focus on and deal with.

As for the front-end, no matter what framework Vue or React, the final result is to call several BOM/DOM apis of the browser, such as createElement, appendChild, removeChild, etc. Therefore, as mentioned above, Taro implements this API using taro-Runtime.

Next, an taro- React package is implemented in React that connects the taro- Runtime to the React – Reconciler, the core of the DOM Tree maintained by React, thereby implementing the render function to generate the Taro DOM Tree. The CreateVuePage methods of Vue also align the processing of some runtime methods, such as life cycles or watch, in the CreateVuePage methods of Vue.

An Taro DOM Tree is generated using the internal Taro plugin. How do you align the Taro DOM Tree with the applet and render it on the applet page?

First of all, we template all the components of the applet one by one, so as to get the corresponding template of the applet component. The following picture is what the view component of the applet looks like after template processing:

<template>
	<view 
      id="{{uid}}"
      class="{{className}}"
      style="{{style}}"
  >
     <block wx:for="{{children}}">  
  			 <template is="{{'tpl_'+item.nodeName}}" data="{{item}}">
			</block>
</template>
Copy the code

Next, we iterate through our Taro DOM Tree and select the appropriate applet template to render the child elements according to the type of each child element. Then, within each template we iterate over the child elements of the current element to recursively traverse the entire node Tree. Finally, you can render successfully on the applet.

/ / Taro dom tree by converting {1: [{ELEMENT type: REPLACE, node:}], 2: [{type: text, content: 'text' children: [...]}]. 3:[{ type:PROPS,props:{class:"content",number:1},... }], ... 10:[{ type:ELEMENT,tage:"ul",childred:[{tag:"li",children:["item"] },...] }] }Copy the code

Of course, you can see that this is a normal virtual DOM tree. similar

const newVnode = h(
  "div#container.two.classes",
  { on: { click: anotherEventHandler } },
  [
    h(
      "span",
      { style: { fontWeight: "normal", fontStyle: "italic" } },
      "This is now italic type"
    ),
    " and this is still just normal text",
    h("a", { props: { href: "/bar" } }, "I'll take you places!"),
  ]
);
Copy the code

So, we dynamically recursively process the DOM tree and convert it to applet format so that it is perfectly displayed on the applet.

<template> <text> Text... </text> ... <ul> <li>... </li> .... </template>Copy the code

So how does the NutUI component library accommodate applets?

As mentioned above, NutUI sets up a separate Taro file for each component, such as Button.taro. Vue. Specifically for Taro’s adaptation. Which directly use view label as a regular container, more suitable for small program conversion.

Let’s look at the contents of this file:

<template> <view :class="classes" :style="getStyle" @click="handleClick"> <view class="nut-button__warp"> <nut-icon class="nut-icon-loading" v-if="loading"></nut-icon> <nut-icon :class="icon" v-if="icon && ! loading" :name="icon"></nut-icon> <view :class="{ text: icon || loading }" v-if="$slots.default"> <slot></slot> </view> </view> </view> </template>Copy the code

At the same time, tarojs**/plugin-html** implements some DOM and event processing.

Has (nodeName){return "text"}else if(specialElements. Has (nodeName)){return "view"}else if( ...) OnAddEvent (type,_hader_,_options,node){if(! isHtmlTags(node.nodeName)) return; DefineMappedProp (node._handlers,type,"tap")}else if(type == "input"){ defineMappedProp ... }}Copy the code

Project optimization and reflection

Of course there will be a lot of problems in the development process, but it is also worth us to record, better service next time development.

routing

Taro does not implement real routing in Vue, but simulates route switching by controlling component reality/hide. So in history, a 10-level limit was made. When jumping with Taro. NavigateTo, you will quickly break through this 10 level. This requires that the navigateTo function be wrapped to prevent overflow. In addition, because there is no real implementation of routing, when page A jumps to page B, page A does not actually disappear, but is hidden by display: None, giving page A unique random ID. Even so, we need to be careful when manipulating DOM elements or setInterval methods in our code. Taro will not refresh the page every time you enter it, nor will you destroy, refresh, and clean up the data after you leave it.

Page content cache

NavigateTo complete the route jump, when A page into B page and then back to A page, in fact, A page has not been re-rendered. It will keep the data from the last time. Achieve the same effect as the Keep-alive component in Vue. However, because no additional lifecycle functions are provided, data is not updated. Even if the driver is forced to update the data, the page will have a flicker change due to the cache of the last rendering, affecting the user experience. Therefore, it is recommended to clean up the current page data during each beforeMount to avoid blinking. At the same time, avoid using navigateTo to jump, and use redirectTo to complete routing.

Listen for page scroll events

In order to adapt to the small program, so the page scroll events can only be listened through onPageScroll, so when I want to listen in the component, I have to advance the logic of this part of the onPageScroll function, increasing the cost of abstraction. For example, when I need to develop a TAB that scrolls to a certain point and hits the top, the logic that could be handled inside the TAB is brought forward, reducing its reusability.

To optimize the

Performance tuning is the focus of every project, and we’ve used a summary of some common tuning points.

conclusion

As the first project completed using Taro + Vue3 + NutUI3, we encountered many problems in development, but also gained a lot. There will be more and more demand scenarios of “one set of code, multiple applications”. We will conduct in-depth practice in more businesses and complete self-improvement.