A 1-year journey of front-end technology framework switching

A 1-year journey of front-end technology framework switching

Summary: With a phone call, I started a one-year journey of switching front-end technology frameworks.

This article is shared from HUAWEI CLOUD COMMUNITY " Remember an Unforgettable Front-end Technology Framework Switching Journey [WEB Front-end Battle] ", the original author: a cabbage.

1. The beginning of the journey

At the beginning of 2020, on an ordinary working day, I was concentrating on "doing things" and received an espace voice from MAE-Access front-end technical experts, and was told that the front-end technology framework used by the MAE-Access domain needs to be switched from AngularJS1.x to React. , It is required to be completed by the end of 2020. When I received the news, I was full of sorrows and joys. Opportunities and challenges coexist. This front-end technology framework switching journey is inevitable, but how to start and how to end.

Question: Why is it "inevitable" for MAE-Access to switch front-end technology framework and FMA LTE of the three base station products?

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

1) FMA LTE integrates two microservices, FMA LTE Website and FMA LTE Service, on MAE-Access, and is constructed uniformly with the entire MAE-Access domain.

2) The MAE-Access domain uniformly provides front-end engineering solutions for each website microservice, and each website microservice uses the front-end UI component self-developed by the Cloudsop platform ---eview. On the one hand, the UI interface style of the network management is unified; on the other hand, it is convenient for the unified management of front-end related open source and tripartite components, and it is also convenient for unified construction.

3)) The eview component provided by Cloudsop has two versions based on the angularJs front-end open source framework and the react front-end open source framework. Since angularJs version of eview uses angularJs1.X, it will no longer meet the requirements of open source tripartite lifecycle management after 21B, so it needs to be unified to react version of eview.

Figure 1-1 Reasons for switching the front-end technology framework

2. travel strategy

2.1 Destination React technical framework and front-end engineering

2.1.1 A brief history of Web front-end development

Before officially introducing React and front-end engineering, let's briefly understand the history of web front-end development. As shown in Figure 2-1, the development of the Web front-end has mainly experienced five key eras.

Figure 2-1 A brief history of web front-end development

Simple and lively early era: suitable for small projects, regardless of front and back ends, the page is generated on the server side by JSP, PHP, etc., and the browser is responsible for displaying.

Back-end-based MVC era: In order to reduce complexity, starting from the back-end, there is an architecture upgrade of the Web Server layer, such as Structs, Spring MVC, etc.

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

Front-end MVC and MV* era: In order to reduce the complexity of front-end development, a large number of front-end frameworks such as Backbone, EmberJS, KnockoutJS, AngularJS, React, and Vue have emerged.

The full stack era brought by Node: With the rise of Node.js, a new development model is brought to the front-end development.

Looking at the changes in the five eras, each post-era is trying to solve the pain points of the previous era.

1) In the era of and , front-end development relies heavily on the development environment; front-end and back-end responsibilities are still entangled, and maintainability is getting worse.

2) In the era, most SPA applications are mainly functionally interactive. There is a large amount of JS code organization, binding with the View layer, etc., which are not easy tasks, and front-end responsibility control is required.

3) In the era of , , the front-end and back-end responsibilities are clear; the front-end development complexity is controllable, and the project is more maintainable through reasonable stratification; the deployment is relatively independent, and the product experience can be quickly improved.

2.1.2 React technical framework

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

React officially explained that React is a JavaScript library for building user interfaces, which makes it easy to create interactive UIs. By using React, you can create components with various states, and these components form a more complex UI. The component logic is written in javascript instead of templates (different from JSP and PHP here), and data can be easily transferred in the application. Separate the state from the DOM.

FMA abolished the original multi-page iframe nesting implementation of the jQuery+AngularJs1.x mashup, switched the React technology framework, re-divided and organized each UI component into SAP, and required a "replacement" rewrite of the entire front end.

2.1.3 Front-end engineering

In order to complete the iterative launch of Web applications with high efficiency and high quality, front-end engineering solutions and related architectures have emerged as shown in Figure 2-2.

Figure 2-2 Front-end engineering architecture

The problem solved by engineering is how to improve the production efficiency in the coding, testing, and maintenance phases. The problems to be solved by front-end engineering include:

1) Formulate various specifications so that the work has rules to follow: unified coding specifications, development process specifications, front-end and back-end interface specifications, etc.

2) Use appropriate front-end technologies and frameworks to improve production efficiency: organize code in a modular way (ES6 Module); use componentized programming ideas to process the UI layer (React); separate the data layer for management (Redux); use Organize the structure in an object-oriented or functional programming manner.

3) Improve the testability of the code, introduce unit testing, and improve the quality of the code.

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

While switching the React technology framework, FMA introduced 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, analyze the changes that will occur in the front-end technology framework switch, from + mashup to + combination, plus the compilation and construction of integrated components/modules, specification checking, automated continuous integration, and deployment. The front-end engineering is actually the transformation and improvement of the software engineering technology of the entire product.

2.2 Play Route-Key Steps for Switching Technical Framework

Play route-key steps for technical framework switching

2.2.1React project construction

1) React project construction: The React official website provides a set of scaffolding projects Create React App for creating React projects, which can quickly create a new single-page React project project that has integrated the standard front-end construction pipeline (can be modified by Parameter configuration of construction tools such as webpack, custom packaging, construction, and debugging projects).

(1) Install Nodejs (a javascript runtime environment) first, download the versions of different operating systems on the official website, and install it with one click.

(2) Install the create-react-app scaffolding tool through the Nodejs package manager tool npm (npm install -g create-react-app)

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

(4) At this point, the project has been created successfully, you can enter the project (cd myproject) and start it directly (npm start). If you need to build a package, execute (npm build). It should be noted that the npm script can be modified or extended by itself in the packge.json file script of the created project.

2.2.2 Development view design and component catalog planning

The mainstream and relatively common directory structure in the industry is shown in the following table. For specific business development, the business itself needs to be divided into directories and files according to the following structure. Basically, you can customize the directories under components and contaniners to divide the components.

| index.js//Entry js | router.js//Route entry | base.css//global style file +---store//redux | | store.js//redux store entrance, here can be used to register middleware | | reducers.js//reducers entrance +---services//Data access (usually api) Each domain is used on demand, without uniform requirements +---contexts//contexts +---utils//Public use method logic +---assets//Resource file | +---i18n//Multilingual | images//Pictures | fonts//font resources | media//Media resources +---constants//Public constants (usually various back-end enumerations) +---components//General display component catalog | +---Header | | index.js | | Header.less |/---NotFound | index.js \---containers//container component directory | +---Todo//Declare the directory of the page | | |---index.js//page entry | | +---components//Page common components | | | +---Button | | | index.js | | | Button.jsx//Recommended usage | | | Button.less | | | Button.stories.js | | | +---Input | | | index.js | | | Input.jsx | | | Input.less | | | Input.stories.js | | +---containers | | | Search.js | | | Body.js | | +---store | | types.js | | action.js | | reducer.js /---test//The results of the test directory and the src directory are consistent +---components//General display component catalog | +---Header | | index.spec.js//Test file for index.js /---containers +---Todo | +---components | | +---Button | | Button.spec.js//Test file for Button.jsx | | +---Input | | Input.spec.js//Test file for Input.jsx | +---store | reducer.spec.js//Test file for reducer.js Copy code

2.2.3 Sorting out front-end components

1) The principle of component division

(1) Standardization: Any component should abide by a set of standards, so that developers in different regions can develop a set of standardized components based on this standard

(2) Independence: Describes the fine-grained components, follows the principle of single responsibility, maintains the purity of the components, opens up APIs such as attribute configuration, and closes the internal state of the components to the outside world, and minimizes the coupling with the business as much as possible.

(3) Reuse and ease of use: UI differences are digested inside the component (note that it is not written a bunch of if/else), input and output are friendly, and easy to use. Avoid exposing the internal implementation of the component, avoid directly manipulating the DOM, and avoid using ref.

2) Component classification and hierarchical relationship

(1) Basic components: In order to pay more attention to the realization of business logic, you can combine your own business and choose a suitable mature UI component library as the basic component library of the entire project. For example, FMA chose the eview UI component provided by the platform.

(2) Container component (Container): a container-like component, generally used as the entrance of a business sub-module, such as the fault overview component of FMA; the sub-components in the container component usually have business or data dependencies; centralized/unified status Management, providing data (acting as a data source) and behavioral logic processing (receiving callbacks) to other display/container-type components; if global state management is used, the business components inside the container can call the global state processing business by themselves; act as a child The state transfer station of the component communication, for the communication coordination of the sub-components in the business module, such as the fault overview component, saves the interface response data of the overview analysis and transfers to the sub-components, and also saves the current interaction status of the sub-components, and has coordinated with other sub-components Interaction and linkage; templates are basically a collection of child components, rarely containing DOM tags.

(3) Stateless: Mainly shows how the component is rendered, just like a simple template rendering process; it only accepts data and callback functions through props, and does not act as a data source; it may contain display and container components and is general There will be Dom tags and css styles; usually props.children(react) or slot(vue) are used to include other components; they can have state, only manipulate and change their internal state during its life cycle, and have a single responsibility, which will not belong to oneself The behavior is passed through the callback, and let the parent component handle it.

(4) Business components: usually abstracted based on the minimum business state, some business components also have a certain degree of reusability, but most of them are disposable components.

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

(6) Logic components: a logical collection that does not include a certain function of the UI layer, such as time processing components and string processing components in FMA.

(7) High-level components (HOC): The combination in analog functional programming can be seen as a function that receives other components as parameters and returns a component with enhanced functions. Such as the ErrorBoundry component in FMA.

(8) The hierarchical relationship of most components of Web applications, as shown in the following figure.

3) FMA component division

Usually can be divided according to business, or according to technology. FMA designs and develops the component tree in the application according to the business.

(1) Cutting template (modular page structure): the main interface is the entrance container component; secondly, it is divided into two panel container components; the left panel is divided into main topo business components and custom topo business components according to business functions; right panel According to business functions, it is divided into business components such as fault overview and fast fault matching. By analogy, components are divided from outside to inside, from large to small, and hierarchically, as shown in the figure below.

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

(3) Clarify the boundaries of each component, the design of the internal state, the design of props and the relationship with other components

(4) Clarify the positioning and function division of each component, and design the communication mechanism of parent-child components and brother components

(5) Set up a shelf and start filling

3. different scenery

After understanding the front-end development history, building a React project, and dividing the components, how to write a React component?

3.1 Single component catalog

First of all, for a single component, there must be a standard component catalog, but the catalog can be tailored through component classification. To create a component, you need to create a separate folder. The folder usually contains the main file entry index.js (the logic of the view layer); the style uses scss or less css precompiled language, written in module.scss/module.less, webpack will automatically compile scss or less into css File, and will solve the difference between browsers; the constant is defined as type.js; the logic processing call interface function is written in actions.js; if you need to use redux, it is defined in the reducers.js file; if the component contains other Business components can be directly nested into a new component folder. For example, the following auxiliary recovery business component catalog.

3.2 The basic structure of the main component 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 04: import'./module.css'; Line 05: 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:'The initialization of the left component is complete!'}); 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 24:} 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>Apple's unit price: {this.applePrice} </p> Line 30: <p>Number of apples purchased: <Spinner Line 31: value={this.state.appleNumber} Line 32: min={0} Line 33: max={100} Line 34: step={1} Line 35: onChange={this.onBuyApple}/></p> Line 36: <p>Total spend: {this.state.totalPrice} Line 37: </p> Line 38: </div> Line 39:) Line 40:} Line 41:} Copy code

1) Line01-05 introduces the react library: import React, {Component} from'react'; including imported third-party components, self-defined components, functions, constants, css files, pictures and other static resource files.

2) Line06-41 implements component class declaration: javascript actually has no concept of class, es6 class is actually a kind of syntactic sugar, and the essence is the constructor Function. Constructor can be omitted. If you don't write it, it will exist by default. It is recommended to add it under the stateful component, and then do the initialization function in Constructor.

3) The line25-40 render function is equivalent to the template in our angularjs, which is used to render to the view above the browser. It should be noted that the React jsx syntax is used here. The style definition uses the className attribute instead of class. The definition format of style is style={{marginLeft:'2rem'}}. The final return element has one and only one Element.

4) The definition and update of view layer variables are fixed. There are two types: automatically triggering the view layer update and not triggering the view layer update. Automatically trigger the view layer to update the relevant state variables, initialize the definition such as line09-13, and re-assign the state variable such as line17, you must use the setState function. Other variables that do not trigger the update of the view layer can be defined directly.

5) React provides hook functions (also known as life cycle functions) for components during initial loading, parameter changes, logout and other actions, similar to those in angularjsonInit,onInit, onChange, $postLink. Among them, the componentWillMount method is called before mounting and render(), so setState will not trigger re-rendering in this method, so you can use setState to change the state value in this cycle; the componentWillReceiveProps method receives and assigns new props to a mounted component Called before, if we need to update the state through props, we can compare this.props and nextProps in this method when they are not equal, and then use this.setState to change the state, so as to reduce the number of unnecessary renderings of the component and achieve performance optimization the goal of.

6) The references of static resources such as pictures are the same as the references of components, which are imported through the import keyword and referenced through attribute variables. Such as Import iconImg from'picture path';. It is recommended to store image resources directly under the current component catalog to avoid deep reference to the catalog.

3.3 component internationalization

1) Use the third-party plug-in react-intl

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

3) Resource initialization and application: Import {injectIntl} from'react-intl'; in the index.js file of the project entry; add <IntlProvider locale={ lang .locale} messages={ lang .messages}> in render . Locale uses language, messages, and requires internationalized language configuration.

Line 01: import {lang, messages} from'./asserts/i18n/index'; Line 02: import App from'./containers/MainContainer'; Line 03: const rootNode = document.getElementById('root'); Line 04: ReactDOM.render( Line 05: <IntlProvider locale={ lang.locale} messages={ lang.messages}> Line 06: <Provider store={store}> Line 07: <div style={{ height: '100%', width: '100%' Line 08: <App/> Line 09: </div> Line 10: </Provider> Line 11: </IntlProvider>, Line 12: rootNode Line 13:); 4) Export internationalized components export default injectIntl (component name); 5) In the specific function of the component, use internationalized resource items such as line01-02 Line 01: const {intl} = this.props; Line 12: const loadingWaitLabel = intl.formatMessage({ id:'loadingWait' }) Copy code

3.4 Background data request

The background data request uses the third-party component axios (a promise-based HTTP library that can be used in browsers and node.js).

1) Axios features: create XMLHttpRequests from the browser; create http requests from node.js; support Promise API; intercept requests and responses; convert request data and response data; cancel requests; automatically convert JSON data; the client supports XSRF defense.

2) Axios request example:

(1) get

//Create a request for a user with a given ID axios.get('/user?ID=12345') .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); Copy code

(2) Post

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

(3) Execute 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 executed })); Copy code

3.5 Redux use

3.5.1 When is Redux

The role of Redux is to solve the communication between parallel components or components without parent-child relationship. Therefore, when two components cannot pass the state promotion and transfer the communication message through the parent component, it is necessary to use Redux technology for message communication.

3.5.2 Redux configuration and use

1) Define the store file and mount 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}); Copy code

2) Application entry index.js global store context configuration,

3) definition of leftPanelReducer.js: types.js+reducers.js+actions.js

(1) types.js

const ACTION_TYPE = { SET_CAT_NAME:'SET_CAT_NAME' }; export {ACTION_TYPE }; Copy code

(2) 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; } } }; Copy code

(3) actions.js

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

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

(1) 1. introduce redux related components in the data transfer component, and modify the global data function setCatName

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

(2) When exporting components, use the connect middleware to associate component properties with the global store. At this time, the setCatName function is equivalent to hanging on this.props, and this.props.setCatName (name) is directly called when using it to modify the global data. Update and notification actions are performed by the entire Redux mechanism.

const mapDispatchToProps = dispatch => bindActionCreators({ setCatName }, dispatch); export default connect(null, mapDispatchToProps)(injectIntl(LeftPanel)) Copy code

5) Use redux to monitor global data updates and accept the latest values, similar to data transfer.

(1) First introduce redux related components in the components,

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

(2) When exporting components, use connect middleware to associate component properties with global store. At this time, the global data catName is hung on this.props, and this.props.catName is directly called when in use. The timeliness of the data is determined by the entire Redux mechanism. Guaranteed.

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

4. the unexpected gain after reaching the end

4.1 Historical debt

1) AngularJs (does not meet life cycle management requirements)/jQuery framework mix and match;

2) Online analysis mode and export report offline analysis mode The source code is separated into two code warehouses;

3) Multiple function modules with 400+ small functions are piled up into "God type", the code duplication rate is 44%, the same business logic is added, deleted, modified and other extended maintenance work, there are problems such as duplication of labor, missing modifications and introducing defects.

4.2 No debt and light weight

Under the background of switching the front-end technology framework (React, single page, UI componentization), the following refactorings were carried out, the source code was exported online, the same business function shared business components, and the code duplication rate was reduced from 44% to 4.8%. Reduce repetitive code 1W+.

  1. Apply the "MVC layering principle" to encapsulate and store data (model), business logic (controller), and interface display (controller) for hierarchical classification of development views, as shown in Figure 2-1;

  2. Apply the "single responsibility principle" and the "least know" principle to sort out the "god class", and extract and encapsulate the stacked functional functions into high cohesion and low coupling pluggable ones according to functional responsibilities. Component class. At the same time, according to the function of the component, it is further grouped and classified into the basic components of the lower layer, the business components of the upper layer, and the tool components for data processing. The upper-level business components can be "combined" to use other business components or basic components as needed. Online analysis and export of report components, similarly combine business components or basic components as needed, as shown in Figures 2-1 and 2-2.

Figure 2-1 Development view hierarchy

Figure 2-2 Component division

3) In order to maximize common business components for export and online, data with different sources and different data structures is standardized and normalized before being transferred to business components.

Figure 2-3 Standardization and normalization of component data

5. postscript

This time the front-end technology framework switch, the transaction itself is relatively passive, fortunately, it can actively identify the difficulties of delivery. Sort out the workload in advance and actively manage the handover process. In the end, the delivery is completed in a timely, effective, and high-quality manner to ensure that the FMA front-end open source components meet the life cycle management requirements, while at the same time improving the front-end software technology of the FMA group, and establishing FMA front-end engineering capabilities from scratch.

1) Combined with the interactive interface block diagram, the business logic and interactive interface of the functional modules are packaged into components. The online and export analysis modes can be highly versatile business components. It is no longer necessary to perform the same or similar function points on two sets of codes at the same time. Development and maintenance, avoid repeated "making wheels", improve development efficiency, improve maintainability and ease of maintenance, and at the same time, avoid the introduction of functional defects due to code modification.

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

Reference link

Click to follow and learn about Huawei Cloud's fresh technology for the first time~