Exploration on the reconstruction of Jushi project

background

The company has an old project with a long history and a large volume. In addition to the characteristics of traditional old projects, the project strongly relies on the back-end template, and each page corresponds to a template. The startup relies on docker. As the project is continuously updated and iterated, The project structure is becoming more and more complex, and the maintenance cost is getting higher and higher, which leads to a series of problems...

Problems with the Monolith App

  • The project size is too large and the clone time is long

  • The structure is chaotic, highly coupled, and difficult to maintain

  • Need to solve the problem of long build time and need to maintain complex webpack configuration

  • When multiple people develop the same project, release deployment is easy to be confused

  • Technology stack iteration costs are high

How to split?

Since it is a megalithic application, the easy-to-think transformation solution is to split it into multiple sub-applications and divide and conquer. Generally speaking, there are the following split solutions:

  • Split by technology

  • Split by business or page

  • Split by authority


  • Splitting our projects according to the frequency of changes does not have the problems of permission restrictions and inconsistent technology stacks. Obviously, these two split methods are not suitable. In our business scenario, a project is composed of multiple pages . The previous states of the two pages are independent of each other. It is obvious to split directly according to the business. The madge tool is recommended here. It can automatically find the dependencies of the entry for you according to the entry you specify, and separate it from the main project and split it. After the completion, which architectural approach should be adopted?

traditional solution

you say repo

That is to directly split it into multiple warehouses, which is simple and crude but has many problems:

Difficult to manage and debug

It is naturally troublesome to manage multiple git warehouses. For modules with similar functions, if they are split into multiple warehouses, multiple warehouses need to be opened no matter for multi-person collaboration or independent development.
Although vscode solves the problem of multi-warehouse management through Workspaces, in the scenario of multi-person collaboration, it cannot guarantee that everyone's environment configuration is consistent.
For shared packages installed through Npm, if you cannot debug the compiled code, or every time you npm link, there is no way to debug the dependent subpackages.

Branch management confusion

If a warehouse is provided for two projects, A and B, and project B prioritizes the development of function b, which cannot be compatible with project A, then a branch of feature/b should be opened in this warehouse to support this function, and it will be merged in the future Sync to project A from trunk.
Once there are more components that need to be branched, and there are dependencies between them, the complexity of branch management will increase exponentially.

Complex dependencies

The maintenance of component version numbers between independent warehouses requires manual operations. Because the source codes are not together, there is no way to analyze dependencies as a whole and automatically manage the dependencies of version numbers. The versions of the three-party dependencies may be inconsistent: an independent package has an independent development environment, it is difficult to ensure that the version of the submodule is completely consistent with the main project, and there is a risk of inconsistent running results.

Take up a lot of space

Under normal circumstances, a company’s business project has only one backbone, and the multi-git repo method wastes a lot of storage space. Repeated installation of large modules such as React may take up dozens of GB of extra space after a long time. For students who do not have an external hard disk It is also troublesome to regularly clean up node_modules under unused projects.

Not good for teamwork

A large project may use hundreds of second-party packages. Different second-party packages have different maintenance frequencies, permissions, and warehouse locations. The main warehouse depends on them in different ways. Once one of the packages is changed abnormally, it will affect the entire project, and we have limited energy, only staring at the main warehouse, and often fall into the release of the humble second-party package.

Code cannot be reused

We said before that our project is strongly dependent on the backend. If it is directly split into multiple projects, the backend code will also exist in multiple warehouses, but because of the entire transformation, we only want to focus on the frontend. Need to be insensitive to the back-end classmates, obviously this way can't be done

modern solution

monorepo

It is a way to manage project code, which refers to managing multiple modules/packages (packages) in a project warehouse (repo), which is different from the common way of building a repo for each module.

Advantage:

  • A set of configurations for multiple projects can be built in batches and released separately

  • There is no need to switch projects back and forth during the development phase

  • You can share code and debug public packages locally without publishing

  • Simplified dependency management, no need to specify version numbers for dependencies, because there is only one common version number for all projects.

  • Depends on reusability

Disadvantages:

  • Warehouse volume is large

  • Commit records are prone to confusion

  • Because it is a warehouse, it is not easy to do separate permission processing for sub-projects

  • Not suitable for automatic release Multiple projects are generally independent releases are not easy to unify

  • Need to manage dependencies yourself

  • The submission history is easy to be confused and needs to be managed by yourself

Applicable scene:

It is suitable for tools and framework projects with strong cohesion, such as React-related and Angular-related. Generally, the release will have a series of dependencies and synchronous updates; at the same time, the development of this kind of project is controllable and will not expand at will, so the volume of the library It is also controllable.

Inapplicable scenarios:

  • Items with uncontrollable volume

  • Projects that need permission management

  • It is not applicable to scenarios where the technology stacks of sub-projects are greatly different

Going back to our business scenario, due to the differences in the construction of various sub-applications, it is not necessary to share a set of construction configurations, and there are factors such as uncontrollable project size and currently only supporting full release, so the modification plan has not been adopted

git submodules + dumb repo

What are git submodules?

Allows you to keep a Git repository as a subdirectory of another Git repository, this allows you to clone another repository into your project and keep your commits separate, the subrepo contains a whole full git repository , even including the .git directory.
Our company also adopts this solution. In our scenario, each page in the Jushi project can be split into an independent project, and then the underlying services, public components, and public methods that all pages depend on are extracted as sub-projects. Warehouse, when modifying sub-warehouses, there is no need to switch projects cd ${子仓库目录}.

Advantage

  • The code is reusable and the debugging cost is low: After splitting out the sub-modules, it is also possible to share a set of common code without installing npm packages and directly debug locally

  • You can run the code of the submodule directly in the disassembled project: therefore, you can put some public services in the submodule, which is suitable for projects that depend on docker or the front and back ends are not completely separated. For example, in our business, just The sub-warehouse maintains a set of back-end templates and docker configurations. When running the host warehouse of the sub-warehouse, you only need to cd ${子仓库目录}run the container, and then proxy the port of the host warehouse to the port 8083 running on the container. The uniqueness of the basic service (backend code)

disadvantage

  • When cloning, you need to clone a sub-project additionally. If the size of the sub-warehouse is too large, the clone time will be too long

  • When modifying a subproject, you need to switch to the repository of the subproject

  • Compared with the form of npm package, as long as the code in the submodule is modified, it will affect the whole body, and there is a risk

  • It only provides a solution to reuse code, and other traditional multi-warehouse problems still exist

webpack5 module federation (Module Federation)

It is also a solution to extract public modules, each sub-application is built separately, and the main application loads the remote module through the container at runtime, that is, the construction of the sub-application. The main application automatically uses the latest resources of the current version of the sub-application. In a word, it can allow an online deployment project to load components in other online deployment projects at runtime.

Fundamental

Imagine that some subsequent loaded modules can be packaged into chunk packages in webpack, and then lazy loaded when this module is used. This situation is usually carried out in the same project.
So can we also package a component and its dependencies into a chunk package in project A, and asynchronously import the chunk package of project A just now according to the agreed address in project B, and run it for use? The answer is Module Federation.

basic concept

  • The remote component provider is called the remote side, and the remote component user is called the host side.

  • A project can be both remote and host, can use components from several different projects, and can provide different components to several other projects.

How does it work?

Example: The project needs to introduce a work order workbench page, as follows:
02a553ab36d3f731d4221a8c508ec6de.png
work order workbench as remote configuration

remote end (work order workbench)

(1) Since both of our projects use the vue3 + vite solution, using the vite-plugin-federation plugin is our best choice. First, you need to install the plug-in on the host side and the remote side, as follows:

yarn add @originjs/vite-plugin-federation -D

(2) Register the components that need to be provided in the plug-in, and provide three-party dependencies that need to be shared
2dee7877a65c625d29b5a3e81e3fef52.png

(3) After the configuration is completed,
the corresponding entry file, chunk file and dependent package file will be generated after packaging on the remote side
92896d37783adeefe852ef594d5c537c.png

host side (IM and phone workbench)

(1) Plug-in configuration, set the remote package address
c2db38d910031c0f3728ab6228eedab4.png

(2) Reference and register components. The main.ts file is as follows
a77c7af5dcb7a25e366d1fd00f21ce1c.png
. Note that ticket-share is the package name registered in the vite plug-in on the host side, and Detail is the component name declared on the remote side exposed (exposes field). In addition to global registration, it can also be referenced anywhere that needs to be referenced.
(3) The use of components is
introduced and used where needed, and props are passed according to business conditions. The use of props is no different from that of ordinary components.
efc778674a423891438ee31031184a01.png
At this point we have completed all the configurations, after that we only need to package and run it online.

How to debug online

Using the Redirector browser extension:
Suppose the microapp's remote entry file is at https://my-federated-app.com/federated/my-micro-app/remoteEntry.js. Then, if I want to use my local development server to handle this app, I can redirect any request containing the pattern /federated/my-micro-app/ to http://localhost:3000 where the development server is running
0cd1be40923d9b7e8b401ec52d4980c0.png

Advantage

  • Low update cost: the introduction of public packages does not need to be packaged and released. Compared with npm packages, there is no need to upgrade the dependent versions of the projects using this package one by one. High Page Level Components

  • Low technical cost: only need to modify the webpack configuration

  • Lazy loading is supported: bundle to load modules only when necessary, improving web performance.

  • Reduce repetitive dependencies: the imported public code can directly use the dependencies of the host environment

  • Flexible splitting, high degree of fine-graining: Compared with git submodules, it can be granular to single-page applications or components. That is to say, he can also replace iframe

disadvantage

  • Without a style isolation mechanism, it is easy to cause style pollution of the main and sub-applications

  • Local development needs to open multiple port services, which is troublesome

  • The maintenance cost of shared packages is high: it is necessary to find out all the packages shared by components. Sharing is sometimes mandatory. If some packages are missed, it may cause page errors or crashes. The same library sometimes needs to be maintained within the agreed version range Inside, sometimes a package that is too old or too new will report an error when loading (but users can choose whether to share it or not)

  • Reasonable planning of chunk splitting is required. If too many chunks are split, the number of requested chunks will be too large, and the amount of concurrency will be too large. If multiple modules share one, the remoteEntryversions of the modules contained in it cannot be managed separately

Going back to our business scenario, since the module federation can only reuse JS chunks, it cannot be reused for the backend services we rely on, so it cannot be used as a basic solution, but it can solve the problems existing in the current code reuse method: because we Each of the sub-projects depends on submodulethe public components and methods in the . Whenever these public components and methods are modified, no matter whether the sub-application needs to modify the calling method or not, it needs to be used in each application to these public components and methods. The recompilation and packaging of the application obviously affects the efficiency. Using the characteristics of the module federation, we can directly launch the submodulecontent on the premise of ensuring that the modification has no side effects. The sub-application is unaware, but Js chunkthe content pointed to by the cdn link has changed.

micro frontend

Micro-frontend is an architecture similar to microservices. It applies the concept of microservices to the browser side, that is, transforms a web application from a single single application to an application that aggregates multiple small front-end applications into one. The micro-frontend architecture has nothing to do with the framework, and each micro-application can be independently developed, run, and deployed independently.

qiankun

Qiankun is a common micro-frontend framework on the market. Take this as an example to talk about its features:
qiankun uses HTML Entrythe method to replace and optimize.

What is HTML Entry?

It is to directly print out the HTML of the sub-application as the entry, and the main frame can obtain the static resources of the sub-application through fetch html, and at the same time insert the HTML document as a child node into the container of the main frame.

After using qiankun for micro-frontend transformation, the page is split into a base application and multiple sub-applications, each of which runs in an independent sandbox environment.

Has the following characteristics:

  • Independence: The main application of the micro-frontend and each sub-application are developed and deployed independently, and to a certain extent, the sub-applications of the micro-frontend can run independently of the main application;

  • Sandbox isolation: sub-applications have their own independent runtime, and the state between sub-applications is not shared, that is, between sub-applications: CSS and JS are independent of each other and will not be polluted by other sub-applications .

  • Framework-independent: Sub-applications can be developed using different frameworks, because in the implementation of existing micro-frontend frameworks, the main application only loads the bundle after the sub-application is built;

  • State sharing: sub-apps can share the state of the main app

It can be seen that its biggest advantage over other solutions is that sandbox isolation has nothing to do with the framework

Applicable scene
  • When a certain part of the monolith application needs to be incrementally upgraded or refactored on the technology stack

  • It is necessary to implement dynamic loading and unloading of front-end applications to improve user experience and resource utilization

  • It is necessary to ensure the style isolation and js sandbox between each front-end application

  • Need to integrate multiple front-end applications into a whole without sacrificing their respective technology stacks and development methods

Not applicable

The complexity of the front end is low, and there is no need for
strong business coupling or data dependence between applications, frequent communication or shared state

Since our project itself is a multi-page project, it naturally supports HTML Entry, and we split the monolith application into multiple small applications instead of aggregating multiple small applications, so there is no problem of inconsistent technology stacks. not a good match

Summarize

No matter which solution is perfect, which one to apply specifically needs to be selected in combination with business scenarios and personal practice

reference

  • https://xie.infoq.cn/article/cab16528dc0ecf3514fdfd492

  • https://www.burhanuday.com/blog/2023/03/devx-and-deployments-in-a-module-federated-micro-frontend

- END -

About Qi Wu Troupe

Qi Wu Troupe is the largest front-end team of 360 Group, and participates in the work of W3C and ECMA members (TC39) on behalf of the group. Qi Wu Troupe attaches great importance to talent training, and has various development directions such as engineers, lecturers, translators, business interface people, and team leaders for employees to choose from, and provides corresponding technical, professional, general, and leadership training course. Qi Dance Troupe welcomes all kinds of outstanding talents to pay attention to and join Qi Dance Troupe with an open and talent-seeking attitude.

76c79fe7aef65f99f5d68b8a9084d128.png

Guess you like

Origin blog.csdn.net/qiwoo_weekly/article/details/130143392