In recent years, with the emergence of the concept of big front end, the boundary between mobile terminal and front end has become increasingly blurred, and a large number of mobile cross-platform development frameworks and modes have emerged. From the early Hybird technologies such as PhoneGap and INOC to the now familiar React Native, Weex and Flutter technologies, all reflect the front-end of mobile terminal development. It has always been the goal of the front end to provide a three-terminal unified development framework, and React Native is such a good three-terminal unified cross-platform development framework. You can refer to the cross-platform analysis in my previous article React Native Mobile Development Field.

Note: This article addresses the React Native component library

Beeshell profile

React Native is a basic component library for React Native applications. Based on version 0.53.3, it provides a complete set of high-quality components out of the box, including JS components and composite components (including Native code). It involves FE, iOS and Android technologies, and takes into account versatility and customization. Support for custom themes for developing and serving enterprise-class mobile applications. Open source: github.com/meituan/bee…

features

It is said that Beeshell has been widely used in many business lines of Meituan Takeout. It has passed the practical tests of various business scenarios, operating systems and models, and has good stability, security and ease of use, etc. Based on this, Meituan open source this product for everyone to use and reference.

  • Consistency and customization of UI styles.
  • Versatility: mainly use JS to achieve, to ensure cross-platform versatility.
  • Customization: we split components in a relatively fine granularity, rely on each other through inheritance, and enhance functions gradually, providing the possibility of inheritance extension and personalized customization at any level.
  • Native function support: Composite components in the component library contain Native code, supporting Native functions such as image selection and positioning.
  • Feature-rich: not only components, but also basic tools, animations, and UI specifications. Complete documentation and use examples.

contrast

Before Beeshell opened source, the React Native community had a number of popular and well-known scaffolding frameworks. Here, component libraries with more than 5000 Github stars are selected for comparative analysis from five dimensions of component quantity, generality, customization, whether native functions are included or not, and the degree of document perfection.

Component library Number of components generality customized Whether native functionality is included Degree of document perfection
react-native-elements 16 Strong, provides a consistent set of UI controls Weak and may need to be overridden for customization no high
NativeBase 28 Strong, provides a consistent set of UI controls In, subject variables are supported is high
ant-design-mobile 41 Strong, provides a consistent set of UI controls In, some can support customization requirements is low
beeshell 25 Strong, provides a consistent set of UI controls Strong, not only supports topic variables, but also supports custom extensions using inheritance is high

By comparison, Beeshell is only slightly inferior in terms of the number of components, and is otherwise consistent or superior to other projects. Because Beeshell had a good system architecture, it was only a matter of time before the number of components was abundant, and our team already had a detailed plan to address the lack of quantity.

The system design

System design is the active process of transforming a practical problem into a corresponding solution. It is the description of the solution. In the general software engineering model, the first step after the completion of requirements analysis is system design. The final stability and ease of use of a project also largely depends on the system design step.

The Beeshell component library is designed to build mobile applications more quickly, provide basic technical support for business development, and greatly improve developer efficiency. However, in the face of different business parties, different functional requirements, different UI specifications and interaction modes, how to effectively take account of all requirements? This put forward higher requirements for system design, the following level of abstraction to reduce the way to detail beeshell system design.

The framework design

Based on React Native, the Beeshell component library interacts with iOS and Android platforms at the system level through React Native. It provides a developer-friendly unified interface to bridge platform differences and provide service support for users to develop business functions. Beeshell acts as an intermediary to ensure the stability and ease of use of basic features of mobile applications. The design principle of its framework is shown below.

The project design

To better introduce beeshell, let’s take a look at some of the design details of Beeshell. On the whole, JS is used as a unified entrance, multi-layer encapsulation hides implementation details, and smooths out the differences between JS and Native, iOS platform and Android platform, which reduces users’ learning and use costs out of the box. Partially based on React Native’s technical characteristics, it is divided into JS component part and composite component part. The development mode of the two parts is “loose coupling”, which enables the Native part to have the ability to replace and change, and improves the flexibility of the component library.

The composite component part can expose the JS interface directly or, if necessary, can be customized wrapped in the JS component part. We try our best to ensure atomicity and simplicity of Native functions, and use JS to achieve unified implementation of any customization requirements. We follow the design principle of JS implementation priority to ensure cross-platform universal features. In order to achieve the above requirements, the following from the JS component part and composite component two parts to introduce.

JS component part design

The design of a software is divided into three design levels: architecture, code design and executable design. We use a top-down approach to design the JS component parts from the architecture.

There are usually seven styles of software architecture: pipes and filters, object-oriented, implicit requests, hierarchies, knowledge bases, interpreters and process controls.

JS component part uses the hierarchical architecture style, the whole is divided into three layers: basic tools, general components, extension components, from top to bottom universality gradually weakened, gradually enhanced customization, function gradually enhanced, through the layered design, each layer plays its own role, both universality and customization.

  • Basic Tools (Common) : The most basic, general section, including JS Utils, animation definitions, UI specifications, and so on.
  • General components: the components with similar functions are classified and sorted into a series. Each series is realized by inheritance internally, with layer upon layer dependence and gradual enhancement of functions. This part focuses on generality and does not consider the requirements of customization to ensure the simplicity of the code. At the same time, components are split in fine granularity, which provides good scalability.
  • Modules: It is the inheritance, extension and combined application of general components. This part focuses on customization and meets business requirements to the greatest extent with low generality.

The extension component part will provide a large number of customized components. If the requirements are still not met, users can learn from the implementation of the extension component to inherit common components on a certain inheritance hierarchy according to their own business requirements, which fully reflects the ability of customization of Beeshell.

Composite component design

The React Native component library includes Native features. The Beeshell component library has completed the integration scheme and specification of Native part, and has good development and use experience, and can continuously integrate Native functions.

The composite component part encapsulates the interface with JS to ensure cross-platform. The Native part is mainly divided into Native Bridge and pure Native. Bridge is the encapsulation of React Native and must be implemented in the component library. The pure Native part can be implemented by Pods/Gradle relying on three parties, effectively absorbing and utilizing the technology accumulation of Native development.

Component library implementation

Cross-platform component

React Native provides built-in components that enable javascript implementation. Some of these built-in components are cross-platform universal components, such as View, Text, and TextInput. Others are implemented separately by the two platforms, such as DatePickerIOS and DatePickerAndroid, AlertIOS and ToastAndroid. Such as:

DatePickerIOS for iOS:

DatePickerAndroid component for Android:

Not only are the functional interactions completely different, but the class names and invocation methods are different, which not only does not meet the business requirements, but also has a high cost of learning and using. There are many similar components, how to erase the differences of flat platform, achieve cross-platform? Our solution is to use JS in preference to implement functionality, which is the design principle of our component library. In view of the above problems, we developed the Datepicker component based on ScrollView, which unified the class name and call method to ensure cross-platform universality. Below is the Datepicker component implemented for Android and iOS.

Datepicker uses JS to fully implement a complete function. However, in some cases, it is not necessary to implement a complete function. We can use the React Native Platform to implement partial cross-platform processing. The TextInput component, for example, does not have a clear button by default on Android, but you can customize it.

Customization Support

With the rapid development of mobile Internet, various kinds of mobile terminal products emerge and develop continuously, which also makes software knowledge continuously popularized, and the positioning of business side on product functions gradually changes from manufacturer-led to user-led. Product functions are more accurate, personalized, refined, deepening is an inevitable trend, through customized services to meet the requirements of product development has emerged. Different industries, different types of products, functions, characteristics are not the same, with a certain established software products to meet different types of demand, its applicability can be imagined. Customization has a good technical architecture and technical advantages, which can be customized, extensible, integrated and cross-platform. It has a good advantage in the processing of personalized requirements, so we need customization.

Style customization

UI specifications are unified from the beginning of the component library design. We according to the UI specification, unified style variables and placed in the basic tools layer, namely beeshell/common/styles/varibles. Js file, in the React Native applications, the style is common js variables, It is easy to reuse and rewrite operations. React Native provides StyleSheet to reduce the frequency of creating new style objects by creating a StyleSheet that uses ids to reference styles. Use StyleSheet. Create and StyleSheet. Flatten flexibly in the component library’s style variable application to get the style ID and style object.

In the implementation of each group, style variables from the underlying tooling layer are introduced beforehand, and uniform variable objects are used instead of defining them in components, thus ensuring consistency in UI style. At the same time, Beeshell provides an API for resetting style variables, enabling one-touch peels. We recommend that beeshell users define style variables in advance when developing mobile applications. Reset beeshell’s style variable with its own style variable; On the other hand, in the development of business functions, we use our own defined style variables to ensure the consistency of the overall UI.

Function customization

Style customization can be realized from the macro and overall perspective, while function customization needs to be analyzed and realized from the micro and local perspective. In the following, the implementation of the Modal series is used as an example to describe the function customization in detail.

The popover interaction on the mobile terminal is generally simpler than that on the PC terminal. We categorise the components similar to the interaction such as the Modal box, drop-down menu and information prompt into the Modal series and implement it by inheritance. One might ask why inheritance and not composition? As mentioned earlier, the main purpose of composition is code reuse, while the main purpose of inheritance is extension. Considering that popover interaction has many customization possibilities, we chose inheritance to achieve better scalability. Let’s look at the implementation:

Masks, pop-up containers, and Fade animations are provided, with the pop-up content portion completely customized by the user. This component is extremely versatile and does not have any custom functions. It should be noted here that the animation part is implemented independently, providing two subclasses of FadeAnimated and SlideAnimated, using the policy mode to integrate with the Modal family, and the Modal component integrates FadeAnimated by default.

Inheriting Modal component, the popup content has made a certain degree of customization expansion, support title, confirm button, cancel button and custom body part of the function, generality weakened, customization enhanced.

So now that we have an intuition of the Modal family, let’s look at the Modal family class diagram and layering.

Complicated conditions

Handle asynchronous rendering recursively

The JS thread and UI thread of React Native application are two threads, which is different from the implementation of the browser using the same thread. Therefore, we can see that the API provided by React Native to operate UI elements is called through callback functions.

React doesn’t require direct manipulation of UI elements, but some components do require complex UI manipulation, such as the Scrollerpicker component, which is implemented entirely with JS.

UI size tolerance mechanism

React Native provides users with a style attribute to control the style of elements, and you can manually set the size of relevant UI elements. However, on some Android machines, the size of the element we set is inconsistent with the size information obtained by measure method. After practical tests on a large number of Android machines, we come to the conclusion that there is an error of a few tenths of a pixel.

Fine layout control

The most common requirement when working with Form components is validation, which is usually built into the Form components of component libraries. However, because there are synchronous and asynchronous verification modes, the verification results can be displayed in various styles and locations, which leads to the complexity of the verification function.

To this end, Beeshell provides the following layout methods: Absolute positioning

The Static positioning

Custom location

What is CVD? Let’s look at a model.

  • The Connector converts user input information into the desired data format.
  • Validator Verifies formatted data.
  • Dependency Handlers handle the dependencies of the current control to other controls.

Each layer carries out immutable data update for a single data source Store, which conforms to interactive cohesion and sequential cohesion with a high degree of cohesion. Each layer uses functional combination to define the callback function corresponding to key (the unique symbol of the form control), avoiding batch if else, which can effectively reduce the ring complexity of the program.

The following uses the Input component as an example to illustrate how CVD works.

test

The ultimate goal of code has two, the first is to achieve requirements, the second is to improve code quality and maintainability, testing is to improve code quality and maintainability, testing code quality.

Unit testing

Unit Testing refers to the examination and verification of the smallest testable units in software. In the days of structured programming, unit testing meant function. The Beeshell component library makes full use of unit testing, done by the component’s developer. Research has shown that full regression testing is required whenever changes are made, especially for components that provide basic functionality, and that testing software products early in the life cycle will best ensure efficiency and quality. The later a Bug is discovered, the more expensive it is to fix it, and unit testing is an opportunity to catch bugs early. The Beeshell component library uses Jest as a unit testing tool, with assertions, test coverage tools, out of the box.

Test case design

The core of the test case is the input data. We will choose representative data as the input data, mainly including normal input, boundary input and illegal input. The following uses the isLeapYear tool function provided in the component library as an example.

The function uses external data, which normal input must have, so 2000 and ‘2000’ are both normal input; Not all functions have boundary input and illegal input. To illustrate the use of examples with both types of input, boundary input is the limit of valid input, where 0 and Infinity are boundary input; Illegal input is data outside the normal value range, ‘xx’ and false are illegal input. Unit testing and code writing are “two sides of the same thing.” You should consider all three of these inputs when coding, otherwise the robustness of the code will be in question.

The tests described above are designed for the functionality of the program, known as “black box tests.” Unit testing also requires the design of test data from another Angle, namely the design of test cases against the logical structure of the program, known as “white box testing.”

White-box testing is also a common requirement, and Jest has a built-in test coverage tool that prints a report of unit test coverage by adding the –coverage parameter directly to the command.

UI Automation testing

Snapshot Testing is a useful tool to ensure that the UI of a component library is not accidentally changed. A typical mobile App snapshot test case process involves rendering UI components, then taking screenshots, and finally comparing them to reference images independent of the test store.

When you test a component in snapshots using Jest, the first time you test a component in Beeshell, you create a snapshots folder in the test directory and save the snapshots in that folder. The snapshot result file is named < component name >.js.snap and contains a TREE of UI components in a certain state. The Button component is used as an example to illustrate how to use snapshot tests.

The snapshot result is as follows:

Static analysis

Another development activity that is often associated with unit testing is Static analysis. Static analysis is the perusing of software source code, looking for errors or gathering metrics, without the need to compile and execute the code.

Static analysis effect is good and fast, can find 30%~70% of the code problems, can be checked in a few minutes, low cost, high income. Beeshell uses SonarQube for static code checking.

SonarQube is an open source code quality management system that supports more than 25 languages. It can be integrated with Eclipse, VSCode and other tools by using plug-in mechanism to fully automate the analysis and management of code quality.

SonarQube provides comprehensive code analysis based on Reliability, Security, Maintainability, Coverage, and communications. Ensure code Quality by setting Quality Gates. Detailed usage can be found in the SonarQube documentation

Beeshell development and use

The beeshell component library is downloaded and used as an NPM package. After the download is successful, it is placed in the node_modules directory of the root directory of the project, and then used by importing beeshell components into the project by importing modules.

So how do we develop component libraries? How to ensure the consistency of the development and use experience of the component library?

First, we need a Demo project. This project is the Development environment for the Beeshell component library. It is a React Native application. We then download and install Beeshell as a dependency on the demo project. Now, the problem becomes how to synchronize beeshell in the node_modules directory with the local beeshell source code.

npm link

As we know, NPM packages can be developed using NPM Link, which works as follows:

However, when we set up the soft link and run the package command, an error was reported. Expected path ‘/ XXX/XXX /index.js’ to be relative to one of project roots

Front-end development usually uses Webpack as a packaging tool, while React Native uses Metro, so we need to analyze Metro here to locate problems.

Metro

After Metro source code analysis, we found that Metro’s packaging scheme is quite different from Webpack. Webpack is based on the entry file, namely the entry attribute in the configuration, recursive parsing dependency, Build a dependency graph Whereas Metro crawls all files under a particular path to build a dependency graph. Analysis shows that Metro’s specific path defaults to the path in the package life run, and the directory below node_modules.

Metro found the global beeshell through a soft link while crawling the file, but did not continue to determine whether the global Beeshell has a soft link, so it was unable to crawl the beeshell source section.

Soft links

Run the ln -s command to establish a soft link between the beeshell package and the beeshell source code under the Demo project node_modules.

This article is reproduced from the original address: tech.meituan.com/waimai-bees…

Attached: Beeshell open source address