Abstract:With one phone call, I started a year-long journey to switch the front-end technology framework.

This article is shared from Huawei Cloud community “remember an unforgettable front end technology framework switch journey [WEB front end big battle]”, the original author: a cabbage.

First, the beginning of the journey

On an ordinary workday in early 2020, when I was concentrating on something, I received an espace voice from a Mae-Access front-end technical expert. I was told that the front-end technical framework used by the Mae-Access domain needed to be switched from AngularJS1.x to React by the end of 2020. On receiving the news, I was mixed with sadness and joy, opportunities and challenges. This journey to switch the front-end technology framework is inevitable, but how to start and how to end.

Q: Why is it “inevitable” for Mae-Access to switch to FMA LTE for three of its base station products?

The reasons can be summarized as the following three points, as shown in Figure 1-1:

1) FMA LTE consists of two microservices, FMA LTE Website and FMA LTE Service, which are integrated on MaE-Access and unified with the whole Mae-Access domain.

2) MaE-access domain uniformly provides front-end engineering solutions for each Website microservice, and each Website microservice uniformly uses the front-end UI component — Eview developed by Cloudsop platform. On the one hand, unify the UI style of the network management; On the other hand, it is convenient for unified management of front-end related open source and third-party components, and also for unified construction.

3) Cloudsop provides eView component, there are two versions based on angularJs front-end open source framework and React front-end open source framework. The angularJs version of the EView will no longer meet the open source triplex lifecycle management requirements due to the use of angularJs 1.x, 21B, and need to be switched to the React version of the EView.

Figure 1-1 Causes for the front-end technical framework switchover

Two, travel strategy

2.1 Destination-React technical framework and front-end engineering

2.1.1 Brief History of Web front-end Development

Before introducing React and front-end engineering, let’s take a quick look at the history of the Web front-end. As shown in Figure 2-1, the development of the Web front-end has gone through five key eras.

Figure 2-1 Brief history of the Web front-end

(1) Simple and bright early era: suitable for small projects, regardless of the front and back end, the page is generated by JSP, PHP and other servers, the browser is responsible for display.

(2) Back-end MVC era: in order to reduce the complexity, the backend as the starting point, with the Web Server layer architecture upgrade, such as Structs, Spring MVC, etc..

(3) SPA Era brought by Ajax: Ajax was formally proposed in 2005, and the front-end development entered the ERA of SPA (Single Page Application).

④ Front-end MVC, MV* era: In order to reduce the complexity of front-end development, Backbone, EmberJS, KnockoutJS, AngularJS, React, Vue and many other front-end frameworks have emerged.

⑤ Full-stack era brought by Node: With the rise of Node.js, a new development mode has been brought to front-end development.

Throughout the five eras, each post-era tries to address the pain points of the pre-era.

1) ① and ② Times, front-end development is heavily dependent on the development environment; Front and back responsibilities remain tangled, and maintainability is getting worse.

2) ③ Times, SPA applications are mainly functional interaction type, there is a large number of JS code organization, and View layer binding, are not easy things, need to carry out front-end responsibility control.

3) ④, ⑤ Times, front and rear responsibilities clear; The complexity of front-end development can be controlled and the project can be more maintainable through reasonable layering. Deployments are relatively independent, and the product experience can improve quickly.

2.1.2React technical framework

From the brief history of Web front-end, React is actually the product of FRONT-END oriented MVC and MV* era, which was born to reduce the complexity of front-end development.

React is a JavaScript library for building user interfaces that makes it easy to create interactive UIs. With React, you can create components with a variety of states that can then form more complex UIs. The component logic is written in javascript rather than templates (unlike JSP and PHP here), making it easy to pass data across the application, keeping the state separate from the DOM.

FMA abolished the original multi-page iframe nesting implementation of jQuery+AngularJs1.x mashup, changed the React technology framework, and redivided and organized each UI component into SAP, which required a “replacement” rewrite of the entire front end.

2.1.3 Front-end engineering

Figure 2-1 shows the front-end engineering solution and related architecture for the iterative online implementation of Web applications with high quality and efficiency.

Figure 2-2 Front-end engineering architecture

The engineering solution is how to improve the productivity of the coding, testing, and maintenance phases. Front-end engineering problems to be solved include:

1) Formulate various specifications to make the work have rules to follow: unified coding specifications, development process specifications, front and rear end interface specifications, etc.

2) Use appropriate front-end technologies and frameworks to improve productivity: organize code in a modular way (ES6 Module); Using componentized programming idea, processing UI layer (React); Separate the data layer management (Redux); Use object-oriented or functional programming to organize the structure.

3) Improve the testability of the code and introduce unit tests to improve the code quality.

4) Improve the overall development and deployment efficiency by using various automated engineering tools (Gulp/Webpack).

When FMA switches React technical framework, it introduces popular front-end engineering solutions in the industry to improve development and maintenance efficiency by means of componentization, modularization, automation and standardization.

To sum up, the analysis of the change of the front-end technical framework switch, from ③+④ mixing to ④+⑤ combination, plus the integration of the compilation and construction of components/modules, specification inspection, automation and continuous integration, deployment of front-end engineering, is actually the transformation and improvement of the entire product software engineering technology.

2.2 Play route — key steps of technical framework switching



Play route – the key step of technical framework switching

2.2.1 Construction of React project

1) React Project construction: The Create React App allows you to quickly Create a new single-page React project that is integrated with the standard front-end build pipeline. Custom packaging, building, debugging projects).

(1) First install Nodejs (a javascript runtime environment), download different versions of the operating system from the official website, one-click installation.

NPM install -g create-react-app install -g create-react-app install -g create-react-app install -g create-react-app install -g create-react-app install -g create-react-app

(3) Open the command line where the project needs to be created, and enter the create-react-app + project name command (create-react-app myProject) to create the project.

(4) So far, the project has been created successfully, you can enter the project (CD myproject), directly start (NPM start). If the package needs to be built, perform (NPM build). Note that the NPM script can be modified or extended in the packge.json file script of the created project.

2.2.2 Development view design and component catalog planning

The following table lists the mainstream and common directory structures in the industry. During the specific business development, the directory and files of the service itself need to be divided according to the following structure. Basically, you can customize the directory under Components and Contaniners and divide the components.

| index. Js/js/entrance | router. Js / / routing entry | base. The CSS / / global style file + - store / / redux | | store. Js / / redux store entrance. Here can be used to register the middleware | | reducers. Js / / reducers entrance + - services / / data access (usually the API) according to the need to use the domain, Do not unified requirements + - contexts / / contexts + - utils / / public use every method of logic + - assets / / resource file | | + -- i18n / / language/images/pictures | | fonts / / font resources Media resources + - constants / / / media/public constants (usually the back-end various enumerations) + - components / / general display components directory | + -- - the Header | | index. The js | | Header. The less | \ - NotFound | index. Js \ | - containers / / container components directory + - Todo / / declaration page directory | | | - index. The js / / page entry | | + -- components / / Page common component | | | + -- -- -- the Button | | | index. The js | | | Button. The JSX / / recommended use | | | Button. The less | | | Button. The stories, js | | | + -- -- -- Input  | | | index.js | | | Input.jsx | | | Input.less | | | Input.stories.js | | +---containers | | | Search.js | | | Body.js | | + -- -- -- the store | | types. The js | | action. Js | | reducer. Js \ - test / / test directory and is consistent with the results of the SRC directory + - components / / directory | general display component + -- - the Header | | index. The spec. Js / / on the index. The js test files \ - containers + - Todo | + -- -- -- components | | + -- -- -- the Button | | Button. The spec. Js / / to the Button. The JSX test file | | + -- -- -- Input | | Input. Spec. Js / / to Input the JSX test file | + -- -- -- the store | reducer. Spec. Js / / to the reducer. Js test files

2.2.3 Sorting front-end Components

1) Principles of component division

(1) Standard: any component should comply with a set of standards, so that developers in different areas can develop a set of standard unified components according to the standard

(2) Independence: it describes the fine granularity of components, follows the principle of single responsibility, keeps the purity of components, keeps the API of attribute configuration open to the outside world, and closes the internal state of components to the outside world, and coupling with business as little as possible.

(3) Reuse and ease of use: UI differences, digestion within components (note not writing a bunch of if/else), I/O friendly, easy to use. Avoid exposing component internal implementations, direct manipulation of the DOM, and use of refs.

2) Component classification and hierarchical relationship

(1) Basic components: In order to pay more attention to the realization of business logic, suitable mature UI component libraries can be selected as the basic component libraries of the whole project in combination with its own business. For example, FMA chose the platform provided eView UI component.

(2) Container: a container-type component, generally as the entry of a business submodule, such as FMA fault overview component; Child components within a container component often have business or data dependencies; Centralize/unify state management, provide data to other presentation/container components (act as data source) and conduct logic processing (receive callbacks); If global state management is used, then the business components inside the container can call the global state to process the business. Act as the state transfer station for the communication of sub-components in the business module to coordinate the communication of sub-components, such as the fault overview component, save the interface response data analyzed by the overview and pass it to the sub-components, and also save the current interaction state of the sub-components to coordinate the interaction with other sub-components; Templates are mostly collections of child components and rarely contain DOM tags.

(3) Stateless components: how the component is rendered, like a simple template rendering process; Accepts data and callbacks only through props and does not act as a data source. It may contain presentation and container components and typically has Dom tags and CSS styles; Usually use props. Children (react) or slot(vue) to include other components; It can be stateful, manipulating and changing its internal state only during its lifetime, having a single responsibility, and passing behavior that is not its own through callbacks for the parent component to handle.

(4) Business components: they are usually abstractions based on the minimum business state. Some business components are reusable, but most of them are one-time components.

(5) Common components: Components that can be used in one or more apps.

(6) Logical component: a logical set that does not contain a function of the UI layer, such as time processing component and string processing component in FMA.

(7) HOC: Analogous to a combination in functional programming, think of it as a function that takes another component as an argument and returns an enhanced component. For example, the ErrorBoundry component in the FMA.

(8) The component hierarchy of most Web applications, as shown in the following figure.

3) FMA component division

It can usually be divided by business, or by technology. FMA designs and develops a tree of components in an application based on the business.

(1) Cutting template (modular page structure) : the main interface is the entry container component; Secondly, there are two panel container components; The left panel is divided into main TopO service components and custom Topo service components based on service functions. Based on service functions, the right panel is divided into service components, such as fault overview and quick fault matching. In the same way, components are divided from outside to inside, from large to small, and in layers, as shown in the figure below.

(2) Design and develop common business components, or basic components, so that the components can be reused as much as possible, such as FMA unique table components, drawing components, etc.

(3) Make clear the boundary of each component, the design of internal state, props and the relationship with other components

(4) Make clear the positioning and function division of each component, and design the communication mechanism of father and son components and brother components

(5) Build the shelf and start filling

Three, different scenery

How to write a React component after understanding the history of the front end, building the React project, and dividing the components?

3.1 Component Directory



First, for individual components, there is a standard component catalog, but the catalog can be trimmed by component classification. To create a component, create a separate folder. The folder usually contains the main file entry index.js(view-level logic); SCSS or less CSS precompiled language, written in module. SCSS /module.less. Webpack automatically compiles SCSS or less into CSS files and resolves the browser differences. The constant is defined as type.js; The logical processing call interface function is written in actions.js; If you need to use redux, define it in the reducers.js file. If the component contains other business components, you can simply nest a new component folder. For example, the following directory of auxiliary recovery business components.

3.2 Basic structure of the component main file index.js

Line 01: import React, {Component} from 'React '; Line 02: import Spinner from '@huawei/eview-react/Spinner'; Line 03: import {injectIntl} from 'react-intl'; Line 03: import {injectIntl} from 'react-intl'; Line 04: import './module. CSS '; Line 07: Import {getTotalPrice} from './actions' Line 06: Class LeftPanel extends Component {Line 07: Constructor (props) {Line 08: super(props); Line 09: this.state = {Line 10: message: ", Line 11: totalPrice: 0, Line 12: appleNumber: 0 Line 13:} Line 14: this. ApplePrice = 2; Line 15:} Line 16: componentWillMount() {Line 17: this.setstate ({message: 'componentWillMount()! '}); Line 18:} Line 19: getDom = (dom) => {Line 20:} Line 21: onBuyApple = (value) => {Line 22:  const totalPrice = getTotalPrice(value, this.applePrice); Line 23: this.setstate ({appleNumber: value, totalPrice}); } Line 25: render() {Line 26: return (Line 27: <div className={"ev_layout_fix left-panel"} ref={this.getdom}> Line 28: <p>{this.state.message}</p> Line 29: <p> < span style = "box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 13px! Important; word-break: break-word! Important;" Min ={0} Line 34: step={1} Line 35: onChange={this.onbuyApple}/></p> Line 36: <p> {this. State. TotalPrice} $Line 37: < / p > Line 38: < / div > Line 39:) Line: 40} Line 41:}

Line01-05 import react library: import react, {Component} from ‘react’; This includes imported third-party components, self-defined components, functions, constants, CSS files, images and other static resource files.

2) Line06-41: javascript does not have the concept of class, es6 class is actually a kind of syntax sugar, the essence is the constructor Function. Constructor can be omitted, otherwise it will exist by default. It is recommended to add functionality under stateful components, and then perform initialization functions under Constructor.

3) The line25-40 render function is equivalent to our AngularJS template, which is used to render the browser view. Note that the React JSX syntax is used, the style is defined using the className attribute instead of the class attribute, the style format is style={{marginLeft: ‘2rem’}}, and the final return Element has only one Element.

4) The definition and update of variables in the View layer are fixed. There are two types: automatically triggering view layer update and not triggering view layer update. Automatically trigger view layer update related state variables, initialization definition such as line09-13, state variable reassignment such as line17, must use setState function. Other variables that do not trigger view layer updates can be defined directly.

$onInit, $onChange, $postLink, $onChange, $postLink, $onChange, $postLink, $onChange, $postLink, $onChange, $onChange, $postLink The componentWillMount method is called before mounting and render(), so setState does not trigger re-render in this method, so you can use setState to change the state value in this cycle; ComponentWillReceiveProps method in a mounted component receives and assignment is called before the new props, if we need to update the state, through the prop can compare this. In this method props and nextProps not equal, This. SetState is then used to change the state to reduce unnecessary rendering of the component and optimize performance.

6) The reference of static resources such as pictures is the same as that of components. Import is carried out through the import keyword, and reference is carried out through property variables. For example, Import iconImg from ‘image path’; <img SRC ={iconImg} Alt = “” />. You are advised to save the image resources directly under the current component directory to avoid referencing the directory too deep.

3.3 Component Internationalization

1) Use the third-party plug-in React-Intl

2) Resource configuration: Create the i18n directory and configure the internationalized resource files.

3) Resource initialization and application: import {injectIntl} from ‘React-intl’ in project entry index.js; Add <IntlProvider locale={lang.locale} messages={lang.messages}> </IntlProvider> to render. The Locale uses the language, messages, the language configuration that needs to be internationalized.

Line 01: import {lang, messages} from './ implies /i18n/index'; The Line 02: import App from '. / containers/MainContainer '; Line 03: const rootNode = document.getelementById ('root'); Line 05: reactdom. render(Line 05: <IntlProvider locale={lang.locale} messages={lang.messages}> Line 06: <Provider store={store}> <div style={{height: '100%', width: </Provider> </IntlProvider>, Line 12: rootNode Line 13: :; 4) Export default injectIntl(component name); Line 01: const {intl} = this.props; line01-02 Line 01: const {intl} = this.props; Line 12: Const loadingWaitLabel = intl.formatMessage({id: 'loadingWait'})

3.4 Background data request

Backend data requests are made using a third-party component, Axios (a Promise-based HTTP library that can be used in browsers and node.js).

1) Axios feature: XMLHttpRequests from the browser; Create an HTTP request from Node.js; Support for Promise API; Intercepting requests and responses; Transform request data and response data; Cancel request; Automatically convert JSON data; The client supports XSRF defense.

2) Axios request instance:

(1) the get

Axios.get ('/user? ID=12345') .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });

(2) Post

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

(3) Perform multiple concurrent requests

function getUserAccount() { return axios.get('/user/12345'); } function getUserPermissions() { return axios.get('/user/12345/permissions'); } axios.all([getUserAccount(), getUserPermissions()]).then(axios.spread(function (acct, perms) {// both requests are now complete});

3.5 Redux use

3.5.1 When to Redux

The purpose of Redux is to resolve communication between parallel components, or components that have no parent-child relationship. Therefore, the Redux technology is used for message communication when two components cannot pass state promotion and the communication message is relayed through the parent component.

3.5.2 Redux configuration

1) Define the store file and attach the store tree.

import {combineReducers} from 'redux';
import {routerReducer} from 'react-router-redux';
import leftPanelReducer from './containers/Home/LeftPanelContainer/reducers';

export default combineReducers({router: routerReducer, leftPanel: leftPanelReducer});

<Provider Store ={store}></Provider>

3) Definition of leftPanelReducer. Js: types.js+reducers +actions.js

(1) types. Js

const ACTION_TYPE = {
    SET_CAT_NAME: 'SET_CAT_NAME '
};

export { ACTION_TYPE };

(2) the Reducers. Js

import { ACTION_TYPE } from './types'; Const initState = {catName: "ketty"}}; export default (state = initState, action) => { switch (action.type) { case ACTION_TYPE.SET_CAT_NAME: { return { ... state, catName: action.data }; } default: { return state; }}};

(3) the actions. Js

import { ACTION_TYPE } from './types';
export const setCatName= catName => dispatch => {
    dispatch({
        type: ACTION_TYPE.SET_CAT_NAME,
        data: catName
    });
};

4) Use redux to pass global data and notify all recipients of the update of global data

(1) Firstly, redux related components are introduced into the transfer data component, and setCatName function is used to modify global data

import {combineReducers} from 'redux';
import { connect } from 'react-redux ';
import { setCatName } from './actions;

(2) When exporting the component, connect middleware is used to associate the component properties with the global store. At this time, setCatName function equals to hang on this.props. When using setCatName, call this.props. The notification action is performed by the entire Redux mechanism.

const mapDispatchToProps = dispatch => bindActionCreators({
  setCatName
}, dispatch);

export default connect(null, mapDispatchToProps)(injectIntl(LeftPanel)) 

5) Use redux to listen for global data updates and accept the latest value, similar to data transmission.

(1) First introduce redux related components into the component,

import {combineReducers} from 'redux';
import { connect } from 'react-redux ';

(2) When exporting components, connect middleware is used to associate component properties with global store. At this time, global data catName is attached to this.props. When using the global data, call this.props.


const mapStateToProps = state => ({catName: state.leftPanel.catName});
export default connect(mapStateToProps)(injectIntl(LeftPanel)) 

Four, after reaching the end of the unexpected harvest

4.1 Historical Debts

1) AngularJs(not compliant with lifecycle management)/ jQuery framework mashup

2) The source code of online analysis mode and export report offline analysis mode is separated into two code storehouses;

3) Multiple function modules of 400+ function small functions are stacked into “God class”, the code repetition rate is 44%, the expansion maintenance work such as the addition, deletion and modification of the same business logic, there are problems such as repeated labor, modification omission and introduction of defects.

4.2 Out of debt, out of trouble

Under the background of switching the front-end technical framework (React, single page, UI componenzation), the following refactoring was carried out. The total source code was exported online, and the same business functions shared business components. The code repetition rate was reduced from 44% to 4.8%, reducing the duplication of code by 1W+.

1) Apply the “MVC Layering Principle” to classify the development view by data encapsulation and preservation (Model), business logic (Controller) and interface display (Controller), as shown in Figure 2-1;

2) Apply the “single responsibility principle” and the “least know” principle to sort out and split the “God class”, and extract and encapsulate the tiled and stacked functional functions into a pluggable component class with high cohesion and low coupling according to functional responsibilities. At the same time, according to the function of the components, the group is further classified into the underlying components, the upper-layer business components, and the tool components used for data processing. Upper-layer business components can be “combined” with other business components or base components as needed. Analyze and export report components online, and combine service components or basic components as required, as shown in Figure 2-1 and 2-2.

Figure 2-1 Development view layer



Figure 2-2 Partition of components

3) In order to maximize the common business components exported and online, data from different sources and with different data structures should be standardized and normalized before being imported into business components.

Figure 2-3 Component data standardization and normalization

Five, the afterword.

This front-end technical framework switch, the transaction itself is more passive, fortunately, can actively identify the delivery difficulties. Organize the workload in advance and actively manage the switching process. Finally, timely, effective and high-quality delivery is completed to ensure that FMA front-end open source components meet the requirements of life cycle management, and at the same time, the front-end software technology of FMA group is improved, and the front-end engineering capability of FMA is established from scratch.

1) combined with interactive interface diagram, the business logic of the function module and interface, after modular encapsulation, online and export analysis mode can be highly common business components, no longer need to two sets of code at the same time, for the same or similar function point development and maintenance, to avoid repetition and created “wheel”, improve the efficiency of development, improve maintainability, easy maintenance, at the same time, Avoid the omission of code modification and the introduction of functional defects.

2) The design and development of business components can be highly cohesive, making their functions single and easy to maintain. In addition, when multiple people cooperate to develop the same functional module, tasks can be divided according to small-grained UI components, parallel development, source code library is not easy to cause conflict, improve the quality and efficiency of development.

Refer to the link

  • https://juejin.cn/post/684490…
  • https://zhuanlan.zhihu.com/p/…
  • https://segmentfault.com/a/11…

Click follow to learn about the fresh technologies of Huawei Cloud