1. Why configure the component platform?

Our goal is to build a platform of “co-construction of configuration component library”, so that all businesses can co-build and use the material library configured by the layout platform, and finally achieve the idea of low code in the middle platform of B-end through the rich material platform.

Positioning: with the ability of “expansibility”, “open co-construction” and “powerful layout components”, providing rich materials for the medium platform of Low Code.

“Configured components” generates components from jsonSchema descriptions as the name implies. Components are assembled according to certain specifications through JSON to meet the different requirements and functions of our business. So what’s the payoff for doing this?

  1. Through the configuration of the technical solution, we can precipitate a large number of business component library, through unified specifications, to build the way of building blocks of each component splicing, through this extended arrangement, so as to achieve the description of the business scene.
  2. Through JSON writing or visual arrangement of components, users do not need to understand the front end, users can expand to more back-end, operation students, just through simple training and rules, you can assemble an MIS page.

2. Technical solution of configured components:

2.1 Explanation of nouns:

Base component library: an official base component library based on ANTD secondary encapsulation. Eg: Button, card, select, etc

Custom components: Components that are published to the platform by component co-authors in accordance with component development specifications that have accumulated functionality in the business.

Blocks: Base component libraries or custom components are meta-subcomponents that are put together using JSON and are parsed by a platform-provided rendering engine called “blocks.”

Official block: an official orchestration of base component libraries and custom components that other business parties can “use” when they encounter scenarios in the business.

Custom blocks: A base component library and custom components that a business party orchestrates according to business requirements.

2.2 Technical Solution:

Configuration platform provides the ability to:

The platform provides component development specifications, access capabilities, JSON renderers, base component libraries, scaffolding, utils libraries

  1. Platform users – Students who participate in building components can take advantage of the scaffolding, common function libraries, and basic component libraries provided by the platform to quickly create and develop “custom components” and publish them to the platform through the scaffolding capabilities.
  2. Platform users – students who have access to platform components can take advantage of the platform’s ability to arrange components. The platform provides the ability to arrange multiple components together according to JSON rules. The user’s combination and arrangement forms a jsonSchema, which can be integrated into its own business with the “blocks” generated by the platform’s rendering engine. Example for service access:
// Sample code -- integrate "blocks" into your own business
import { Render } from '@scope/lego-x-core' // Platform-provided rendering engine

class Page extends React.component { 
	render () {
		<Render schemaJson={{... }} /> // Json generated by the user defined orchestration component, with "blocks" generated by the rendering engine}}Copy the code

3. Configuration component development specification:

Objective: To develop the specification, in order to facilitate the unified convergence of configuration components, so that the students who choreograph components experience the same; Make the components themselves highly extensible.

Dependence: Since most of our current business projects are based on ANTD3 and ANTD4 component libraries, our configuration component library selection is based on the secondary development of ANTD component library and compatible with ANTD3 and ANTD4.

3.1 schema specification

 {
    id: '1'.// The unique id of the component
    xComponent: 'Acomp'.// The component name
	version: '1.0.2'.props: { 
	  visible: true.// Whether to display
	  cols: [ // Common props data
        6.11].antdProps: {}, // Inherit antd attributes
    },
    children: [ // Nested relationships
      {
        id: '2'.xComponent: 'Acomp'.props: {
          id: 1, 
          onChange (value) {
            // Each component inherits the base class component, and $emit the public hooks exposed by each component
            // Implement one-to-one or one-to-many linkage by calling functions
			if (value === 2) {
				this['3'].$emit({
            	 	visible: false})}else (value = 3) {
				this['3'].$emit({
            	 	disabled: true})}},tpl: 'This is document ${uid}'.// Template - own component data
          antdProps: {}},}, {id: '3'.xComponent: 'Bcomp'.props: {
           visible: true.id: 1111.// Props data
		   onClick () {
				const res = getApi('http://www.baidu.com');
				this['4'].$emit({
					dataList: res
				})
		   },
           getDataApi: { / / Api request
				url: 'http://www.baidu.com?id={this['2'].state.uid}' / / template
				method: 'get'}}}, {id: '4'.xComponent: 'Ccomp'.props: {
           state: {dataList: []},}}]}Copy the code

3.2 How Do Components Communicate

  1. Scene 1:

If option 1 is selected A, option 2 is hidden; If option 1 is selected, option 2 is disabled

  1. Scene 2:

Option 2 asks the interface to return data during onChange, giving option 3

Analysis: “Daily development of business components” : data is driven by props, the data of props is changed, and the sub-components are re-rendered. The configured component is described by a set of jsonSchema. After the jsonSchema is determined, it will not be changed. However, to realize the linkage of multiple configured components, a unified specification is required to trigger the changes of the “props” of the components.

Solution: When the renderer parses Json, the renderer engine maintains the props data of the jsonSchema in the global store. Other components can be modified with the props of option 2 and re-rendered with the Render of option 2 components via the $emit method.

{{id: '1', xComponent: 'Acomp', props: {// The framework maintains props in a global store. The other components can use $emit to change this data and re-render the function. id: 1, onChange (value) {// each component inherits the base class component, and $emit each component exposes the public hook // by calling the function: If (value === 'A') {this['2'].$emit({// this points to the global store; $emit({disabled: true})} $emit({disabled: true})} $emit({disabled: true})} $emit({disabled: true})} $emit({disabled: true})} ${uid}', // template - own component Data antdProps: {}},}, {id: '2', xComponent: 'Bcomp', props: {visible: Const res = getApi('http://www.baidu.com'); const res = getApi('http://www.baidu.com'); this['3'].$emit({ data: res }) }, } }, { id: '3', xComponent: 'Ccomp', props: { data: "", } } }Copy the code

Who does this point to in the onClick method? Points to the global store. When the renderer parses json and finds a function type, it rebinds this — props. OnClick = props. Onclick.bind (store)

Advantages: Good scalability, basically can meet most scenarios.

3.3 jsonSchema data request specification

api: { url: 'http://www.baidu.com?id={this['1'].id}', method: 'GET', headers: {}, dataType: 'json',// blob, text, etc. successCallback (res) {//status=200, This ['common'].error(' error ') return res} failCallback (res) {// status! This ['common'].error(' error ') return res}}Copy the code

Data interface requests are often involved within components (such as Select above). The data can be obtained through external props or through the API shemaJson specification, which integrates the request interface internally. The generic request request is provided by @scope/ Lego-X-core

3.4 Layout Specifications

The official base configuration component library contains layout components – grid, Flex components

____Grid {id: '1', xComponent: 'Grid ', // props: {columns: [{span: 6, offset: 1, children: [{id: '2', xComponent: 'aComp' }] }, { span: 6, offset: 1, children: { id: '3', xComponent: 'aComp' } }] } } ____Laoyout { id: '1', xComponent: 'Layout', props: { columns: [ { style: Children: [{id: '2', xComponent: 'aComp', props: {id: 2}}]}} child: [{id: '2', props: {id: 2}}]}}Copy the code

3.5 Style Specifications

The configuration component library is generally used by multiple systems. In order to ensure the uniformity of styles, styles should be simplified as much as possible to reduce the additional complexity and visual cost brought by styles.

The basic component library and custom components are based on ANTD. If you need to modify the style theme, you can achieve it through antD – Custom Theme.

Special processing styles are required. Components can expose className and style parameters for style copying.

{
    id: '3',
    xComponent: 'Ccomp', 
    props: {
		style: 'comp-class-name',
       	dataList: [],
    }
}
Copy the code

3.6 Component development specifications

Import {observe, render, utils} from '@scope/lego-x-core' import {observe, render, utils} from '@scope/lego-x-core' import {observe, render, utils} from '@scope/lego-x-core' Class Acomp extends React.Component {... Render () {const {title, children // to render the child node, ignore it if it is a leaf node. } = this.props; Return (<div className="page"> <h1>{title}</h1> <div className="body-container"> {render(children) /* Render the children node */} </div> </div> ); } } export default AcompCopy the code

4. Frame design of rendering engine & basic components

4.1 Multi-package Architecture

Lerna is used for multi-packet architecture. It can be divided into core package and basic component library functions. The partition and output files of NPM package are as follows:

Underlying core core package

The package name is @scope/ lego-X-Core, its core function is “renderer function”, and the utility class library (EG: evalTemplate, request). This package provides common capabilities for base component and custom component development.

Base component library: Package named @Scope/Lego-X-Components outputs NPM package and UMD module. ├─ Build ├─ Dist ├─ Lerna. Json // ├─ Package │ ├─ Components Output @ the scope/lego - x - components │ │ ├ ─ ─ package. The json │ │ └ ─ ─ the SRC │ │ └ ─ ─ card based component / / directory │ │ ├ ─ ─ demo │ │ ├ ─ ─ index. The js │ │ ├ ─ ─ Lib │ │ ├ ─ ─ the SRC │ │ └ ─ ─ style │ ├ ─ ─ the core / / component underlying dependence, Output @ the scope/lego - x - core │ │ ├ ─ ─ package. The json │ │ └ ─ ─ the SRC | | ├ ─ ─ Render / / exposed the renderer to access system, the arrangement of the renderer and composition of jsonSchema, form a "block" function, It can be connected to the service system. │ │ ├ ─ ─ render / / schemaJson specification is to support the nested components, in the development of basic component library or custom component, if can be nested inside other components, can render function resolution nested components │ │ └ ─ ─ utils/tools/component library, ├─ packge.json ├─ scripts ├─ site // Show website, preview function ├─ test // unit Test, coverage test file directoryCopy the code

4.2 Renderer design

4.2.1 Component mapping to schemaJson

React components for daily development:

<Tab>
	<TabPane title="tabl">
		<Table />
	</TabPane>
    <TabPane title="tab2">
		<Form />
	</TabPane>
</Tab>
Copy the code

Parsed into schemaJson:

{
    id: '1',
    xComponent: 'Tab', 
    props: {
	   columns: [
		{
		  	title: "tabl"
		  	children: [{
				id: '2',
            	xComponent: 'Table'
		  	}]
	   	},
		{
			title: "tab2"
		  	children: [{
				id: '2',
            	xComponent: 'Form'
		  	}]
		}]
    }
}

Copy the code

4.2.2 Life cycle design

The renderer mainly parses schemaJson above. When the xComponent field of the schema is encountered, it is possible to identify the component value, load the corresponding component on demand, register the component (the reason for adding this step is that the next time you encounter a component with the same name, you don’t need to import it again on demand), and parse the component for rendering. If the component has received the children field of props, it continues to call the Render function of the renderer.

Access system using renderer sample Example of an internal renderer implementation Example custom component implementation

5. Customized solutions for automatic integration of components into the platform

5.1 Develop scaffolding for “custom components”

  1. Consideration of building UPM module to publish to CDN in packaging mode:
  • Dynamic integration of custom components into platform functions -- after the developer releases components, the platform does not need to go online, and the corresponding CDN address can be loaded according to the rules.Copy the code
  • Access System When accessing blocks, the system can load corresponding components as required to reduce the size of packetsCopy the code
  1. Considerations for converging component source code to a unified repository:

Custom components have the “open” property. In order to ensure the long-term stability of components, the platform will host the source code.

5.2 Component Version Management

5.2.1CDN File naming conventions

Packages contain hash and latest versions to distinguish component versions. Such as:

Unpkg.com/lego-x-comp…

Unpkg.com/lego-x-comp…

5.2.2 Basic Component Library

Any updates to the base components require an NPM package, and all components share a common version number.

5.2.3 Customizing Components

NPM package is required for component update. This must be done using the scaffolding tool. If you use NPM run publish yourself, the latest component changes will not be synchronized to the configuration platform.

5.2.4 How can USERS who access the System customize the version

{id: '1', // unique id of the component xComponent: 'Acomp', // Name of the component version: '1.0.2', // Specify version, if not, use latest version: {}}Copy the code

5.3 Platform database design

6. Extension – Target of Low Code

7. QA

7.1Q: Can I directly use the “ANTD” component library when developing custom components?

A: The official configuration base component library is based on “ANTD” implementation, internally compatible with ANTD3 and ANTD4 versions. In principle, “custom component library” development directly use the official “base component library”.

If the official base component library is incomplete and some of antD’s components are not covered, the “custom component library” can also use antD directly. But development, as far as possible compatible with “ANTD3”, “ANTD4” API.

7.2 How can I upgrade a Service Component developed by Q to a Configured Component?

A: “Daily development of business components” : data is driven by props. Data of props is changed and sub-components are re-rendered.

Configured components: are described by a set of jsonSchema. After the jsonSchema is determined, it will not be changed. However, to realize the linkage of multiple configured components, minor changes need to be made according to the specifications.

We maintain the principle of “try not to change the code as much as possible” and will document it in detail later.

7.3 The Q component is developed by “React” and the access system is Vue. Can I use the access component?

For Vue systems, the official renderer container of the Vue technology stack will be provided to be compatible.

7.4Q” Custom Component “has the property of” open “. The component is not maintained. What should I do if there are new requirements for accessing the system?

A: Converges component source code to a unified repository to ensure that the code will not be lost because of “random”.

B: When the component is in “no maintenance” state, the component will be displayed on the platform in the “down” state, so that the new access system can realize that the component is not in maintenance state.

C: The platform coordinates subsequent maintainers of this component.