Refresh the page? Route splitting? No, dynamically load components.

This paper is divided into the following four parts:

  • Introduction to the concept of front-end microservitization

  • Design concept of micro front end

  • Actual micro front-end architecture design

  • Front-end microservitization based on Mooa

The front end is incognito

There are some solutions for front-end microcogging:

  • Web Components obviously make a good infrastructure. However, it is not possible to copy existing applications on a large scale.

  • The iFrame. Are you serious?

  • Single-spa, another micro-front-end framework, is clearly a better approach. However, it is not Production Ready.

  • The application is segmented by route, and this jump affects the user experience.

  • And so on.

Therefore, when we consider front-end microservitization, we want to:

  • Independent deployment

  • Independent development

  • Technology has nothing to do

  • User experience is not affected

Independent development

Over the past few weeks, I’ve spent a lot of time learning the code for Single-SPA. However, I found it too cumbersome to develop and deploy, and not up to the standard for standalone deployment. With single-SPA’s design, I need to name my application in the entry file before I can build:


     
  1. declareChildApplication('inferno', () => import('src/inferno/inferno.app.js'), pathPrefix('/inferno'));

Copy the code

Also, in my application, I need to specify my life cycle. This means that when I develop a new application, I have to update two pieces of code: the main project and the application. At this point, we’ll most likely be working on the same source code.

Working in the same source code can become quite unreliable when multiple teams are involved – for example, the other team uses Tab, we use 2 Spaces, and the other team uses 4 Spaces.

Independent deployment

The biggest problem with a single front-end application is that the JS and CSS files constructed are quite huge. The micro front end means that the file is split into multiple files that can be deployed independently.

Do we really need technology irrelevant?

Wait, do we really need technology? If we didn’t need technology agnostic, the micro front end problem would be easy to solve.

In fact, for most companies and teams, technology irrelevance is just a trivial matter. When several founders of a company use Java, there is a good chance that they will continue to use Java for future selections. Unless, that is, some additional service uses Python to implement artificial intelligence. Therefore, in most cases, it is still unique to the technology stack.

This is especially true for front-end projects: there is basically only one framework in a department.

So we chose Angular.

User experience is not affected

It is a simple and efficient way to use route jump to implement front-end microservitization. However, there will be a blank screen during the route jump. In this process, both the app before the jump and the app before the jump lose control of the page. If something goes wrong with the app, the user will be stunned.

Ideally, it should be manageable.

Design concept of micro front end

Design concept 1: Centralized routing

Is the Internet decentralized by nature? No, DNS decided it wasn’t. TAB determines that it’s not.

Microservices, by their nature, should be decentralized. But it can’t be completely decentralized. For a microservice, it requires a service registry:

The service provider must register the notification service address, and the service caller must be able to discover the target service.

For a front-end application, this is routing.

Menu

In terms of pages, only when we add a menu link on the page can users know that a page is available.

404

In code, we need a place to manage our applications: ** Discover which applications exist and which applications use which routes.

Managing our routing is really managing our application.

Design idea 2: logo application

When designing a micro-front-end framework, I struggled with the problem of giving each project a name — how to normalize the thing. Until, once again, I thought of Conway’s law:

System design (product structure equals organization form, each design system organization, its resulting design equals communication structure between organizations.

Conway’s law

In other words, it is impossible for two projects in the same organization to have the same name.

So, the problem was solved very simply.

Design Idea 3: Life cycle

Single-spa designs a basic lifecycle (although it is not uniformly managed) that includes five states:

  • Load determines which application to load and binds the lifecycle

  • Bootstrap to obtain static resources

  • Mount to install the application, such as creating a DOM node

  • Unload deletes the application life cycle

  • Unmount: unmounts an application, for example, deleting a DOM node

So I basically stuck with this life cycle in my design. Obviously, things like load are redundant in my design.

Design concept 4: independent deployment and configuration automation

In a sense, the entire system revolves around application configuration. If the configuration of the application can be automated, then the entire system can be automated.

When we only develop a new component, we just need to update our component and update the configuration. The configuration itself should be automatically generated.

Actual micro front-end architecture design

Based on the above premise, the working process of the system is as follows:

System workflow

The overall engineering process is as follows:

  1. When the main project is running, it will go to the server to get the latest application configuration.

  2. After obtaining the configuration, the main project creates applications one by one and binds the application life cycle.

  3. When the main project detects a route change, it looks for a corresponding route to match the application.

  4. If the matching application is matched, the corresponding application is loaded.

Therefore, its corresponding architecture is shown in the figure below:

Architecture

Independent deployment and configuration automation

Our deployment strategy is as follows: our application uses a configuration file called apps.json, and the main project gets this configuration. Each time we deploy, all we need to do is point apps.json to the latest configuration file. The configured file classes are as follows:

  1. 96a7907e5488b6bb.json

  2. 6ff3bfaaa2cd39ea.json

  3. dcd074685c97ab9b.json

The configuration of an application is as follows:


     
  1. {

  2.  "name": "help",

  3.  "selector": "help-root",

  4.  "baseScriptUrl": "/assets/help",

  5.  "styles": [

  6.  "styles.bundle.css"

  7. ].

  8.  "prefix": "help",

  9.  "scripts": [

  10.  "inline.bundle.js",

  11.  "polyfills.bundle.js",

  12.  "main.bundle.js"

  13.  ]

  14. }

Copy the code

The selector here corresponds to the DOM node required by the application, and the prefix is used on the URL route. These are automatically generated from the index.html file and package.json.

Inter-application routing – events

Because now the application becomes two parts: main engineering and application. There is a problem: only one project can capture route changes. When the secondary routing of the application is changed by the main project, it cannot be effectively communicated to the sub-application. In this case, the child application can only be notified by event, and the child application also needs to monitor whether it is the route of the current application.


     
  1. if (event.detail.app.name === appName) {

  2.  let urlPrefix = 'app'

  3.  if (urlPrefix) {

  4.  urlPrefix = `/${window.mooa.option.urlPrefix}/`

  5.  }

  6.  router.navigate([event.detail.url.replace(urlPrefix + appName, '')])

  7. }

Copy the code

Similarly, when we need to jump from application A to application B, we also need A mechanism like this:


     
  1. window.addEventListener('mooa.routing.navigate', function(event: CustomEvent) {

  2.  const opts = event.detail

  3.  if (opts) {

  4.  navigateAppByName(opts)

  5.  }

  6. })

Copy the code

The rest, such as Loading animations, are similar.

Use Mooa

So, we have Mooa, the front-end microservices framework. It is based on single-SPA && single-spa-Angular-CLI and conforms to the above design ideas.

GayHub address: https://github.com/phodal/mooa

For the main project, only a few lines of code are required to do the above:


     
  1. http.get<any[]>('/assets/apps.json')

  2.  .subscribe(data => {

  3.  data.map((config) => {

  4.  that.mooa.registerApplication(config.name, config, mooaRouter.matchRoute(config.prefix));

  5.  });

  6.  this.mooa.start();

  7.  });

  8. this.router.events.subscribe((event: any) => {

  9.  if (event instanceof NavigationEnd) {

  10.  that.mooa.reRouter(event);

  11.  }

  12. });

Copy the code

Add a subapplication route:


     
  1. {

  2.  path: 'app/:appName/:route',

  3.  component: HomeComponent

  4. }

Copy the code

The four steps described above.

For sub-projects, only one corresponding Hook operation is required:


     
  1. mooaPlatform.mount('help').then((opts) => {

  2.  platformBrowserDynamic().bootstrapModule(AppModule).then((module) => {

  3.  opts['attachUnmount'](module);

  4.  });

  5. });

Copy the code

And set the corresponding base_href:


     
  1. providers: [

  2.  {provide: APP_BASE_HREF, useValue: mooaPlatform.appBase()},

  3. ]

Copy the code

Well, it’s that simple. The DEMO video is as follows:

For the Demo address, see http://mooa.phodal.com/

Making sample: https://github.com/phodal/mooa


If you have the money, make a lot of money

If you don’t have money, pay attention