Micro Frontend with Single SPA
Explore how an open source library single-SPA helps to achieve a micro frontend web application implementation design.
**Micro Frontend with Single SPA**
<big>An open source library to implement Micro Frontend application </big>
by Vimal Dhale
<small>© 2022, GlobalLogic, A Hitachi Group Company
1741 Technology Drive
San Jose, California
95110
<a href="https://www.globallogic.com/"> www.globallogic.com</a>
<a href="mailto:info@globallogic.com">info@globallogic.com</a>
All rights reserved. No portion of this book may be reproduced in any form without permission from the publisher, except as permitted by U.S. copyright law. </small>
**Important! Tips for Getting the Most Out of This Content**
Click the 'Read on' button below to get started.
Navigating This Guide
< > From a chapter introduction page, right or left-facing arrows enable you to go forward or back between chapters.
Read on takes you into the chapter to access all content.
'Home' returns you from anywhere in the document to this page.
< > Once inside the chapter, arrows enable you to flip through content pages or move to the next chapter.
Table of Contents
Or, navigate directly to a section of your choice below.
Introduction
Micro Frontend (MFe) is a web application implementation design idea that breaks the traditional monolithic way of implementing large or mid-scale web applications. MFe allows teams to work separately with their frontend technology and addresses a common problem.
In this document, we’ll discuss an open source library single-SAP that helps to achieve the MFe design. Then, we’ll focus on how a single-SAP addresses basic questions regarding an MFe design.
There are other ways to accomplish the MFe design, but this application has continuously upgraded and is stable daily. Here is an example of an MFe design.
Root Application
The root application needs to be shared by every MFe application. It has an HTML file that is a placeholder for all your MFe apps. The root application registers all the MFe apps and is responsible for bootstrapping, mounting, or unmounting the MFe into the DOM.
import {
registerApplication, start } from 'single-spa';
The register application function is used to register all your MFe apps. The start function will not be bootstrapped, mounted, or unmounted until the application is loaded. The entire process is known as the configuration setting.
There are many different functions that provide more control over the flow of the design, such as the triggerAppChange, navigateToUrl, getMountedApps, getAppNames, getAppStatus, unloadApplication, unregisterApplication, addErrorHandler, removeErrorHandler, pathToActiveWhen etc. Note that the root app configuration is the most important step of the MFe design.
Home
MFe apps should be handled with routes as much as possible. For example, don’t overuse an MFe within another MFe application. This way, the MFe apps don’t need to share the UI state.
The applications will always be created and destroyed when they share the same route. Therefore, you shouldn’t share UI states between MFe apps.
The single-SPA has categorized the MFe design into three parts, including:
- Application
- Parcel
- Utility
Application
The application is the core building block of the MFe design. When it’s integrated with the root application, it will serve a specific purpose.
For example, the application may export public interfaces like components, UI state, value, parcel, or methods – and it must have its routes. It should also manage its lifecycle when it gets mounted, unmounted, and bootstrapped. These may also have interfaces that have to be imported by an MFe application.
Parcel
The parcel is like a web component. It does not have any routes and requires a custom lifecycle, which means the other application will have control when it gets to mount, unmount, and bootstrap.
The parcel is best suited when a UI feature needs to be shared across applications. The parcel can be small like a function or as big as an application.
Parcel-based MFe implementation is not recommended as it will require UI states to be shared between MFes, but it cannot be completely avoided. It is useful if the MFe applications are developing on different platforms.
The parcel may have its own deployment strategy with its own repository, or it can be a public interface of an application.
Utility
The utility applications have public interfaces. It doesn’t have any routes or UI to be rendered. Instead, it contains the logic that must be shared across the MFe applications.
The possible utilities that can be shared across MFes are:
- Notification service
- Styleguide/component library
- Error tracking service
- Authorization service
- Data fetching
The utilities may have separate deployment processes and repositories, such as applications and parcels. See here how these will appear when working together:
Home
Routing & Inter-app Communication
Routing
The single-SPA has a layout engine that can be installed via the single-spa-layout npm package. It provides a routing API to manage the top-level routing. The layout engine is a built-in feature by the single-SPA library to implement the routing of MFes.
The design may have an MFe for navigation only, and the layout needs to be defined in the root application’s index.html file. The library has a well-defined list of APIs for the layout flow.
Inter-app Communication
A good architecture is one in which micro frontends are decoupled and do not need to frequently communicate. Route-based single-spa applications inherently require less inter-app communication.”
An MFe design is where there are significantly fewer inter-app communications.
Below are the points where two MFes need to communicate:
Functions, components, logic, and environment variables
The public interface must be created to share a function, component, logic, or environment variable.
API Data
It’s not recommended to share the API data between MFes. Instead, if needed, an in-memory JavaScript cache of API objects is the way.
UI State
The UI state is not supposed to be shared between MFes. If two MFes frequently share the UI states, they should be merged into one MFe. Still, if at some point it’s required, then, RxJS, Custom Events, or sub-sub are the available options.
State Management
You shouldn’t use the single-SPA team with any state management library within the MFe design. If you have to use it, state management shouldn’t be used at the central level, so there shouldn’t be a common store across all MFes. Instead, the single application may have its own stores. Using a common store will break the concept of an MFe.
Home
Local Development & Testing
Local Development
The local development strategy should work only on the MFe we want to use and everything else (the MFe, parcel, or utility) in its deployed versions. There could be two approaches. One is to use the tool import-map-overrides. This will allow you to switch to the local or deployed version immediately. It will also be helpful to perform testing.
The other approach is to use a stand-alone method. This will require using the root config locally. The better approach is to use the import-map-overrides as it provides the complete prod-like experience to the developer.
Testing
Performing unit or end-to-end testing is similar to testing any other front-end application with some exceptions.
Unit Testing
Everything else is similar to a unit test of applications, parcels, or utility except for two points. One is when an MFe is imported to another MFe application because the unit test is usually performed locally, and there we will not have access to other MFe. The solution is to mock the other MFe. The second exception is when system.import is used to load another MFe asynchronously.
Here, we need to again mock the SystemJS and imported modules. The point to be noted is that system.import returns a promise, meaning the tested area would be asynchronous and wait to resolve the promise.
E2E Testing
There are two possible approaches to performing e2e testing. One is to test the application as a stand-alone. With this, the root config cannot be tested properly if some initialization or configuration has been done at this level. In this case, it is better to mock the root config for one application only.
The other e2e testing approach is to test everything else together. In this case, the configuration would be the same as a prod environment. In this case, a tool called import-map-overrides provided by the single-SAP could be useful.
Deployment and Continuous Integration (CI)
The MFe (application, parcels, or utility) must build and deploy independently. Monorepos is not the way to go for the MFe design. There should not be a centralized repository. There are two deployment steps:
1. Upload a new javascript bundle to the cloud. The Javascript bundle should be completely static.
2. Point the import map to the newly uploaded file.
Best Practices
✔️ The MFe design should be route-based to reduce the maintenance of the UI states across MFe apps.
✔️ Create the parcel if the same UI is used in multiple MFe apps.
✔️ Create the features of data fetching, style guide, error logging, notification, etc., as a utility.
✔️ The MFe apps may have some features shared as a public interface.
✔️ The MFe apps should not interact or have significantly less interaction. If its frequency is too much better, merge those MFe apps into one.
✔️ Import-map-overrides is the tool for local development as well as for testing.
✔️ There should not be a common store (state management) across all MFe. The store can be at one application level only.
✔️ It is better to have standard frontend technologies for all the MFe.
✔️ Do not use mono repos.
Home
Conclusion
The MFe is slowly emerging as an entirely new way of providing front-end application solutions.
The single-SPA is one of the more stable, mature libraries, and many APIs have been developed under this framework.
There are a lot of starter applications as well, which can be used to build an actual application.
Author
<big>Vimal Dhale is a frontend enthusiast and expert in Angular and JavaScript who has designed and led sophisticated frontend applications in the Healthcare and Telecom domains. Vimal believes in developing strong technology teams by identifying growth areas for them to work in.
About GlobalLogic
A Hitachi Group Company
About GlobalLogic
GlobalLogic is a leader in digital engineering.
We help brands across the globe design and build innovative products, platforms, and digital experiences for the modern world.
By integrating experience design, complex engineering, and data expertise—we help our clients imagine what’s possible, and accelerate their transition into tomorrow’s digital businesses.
Headquartered in Silicon Valley, GlobalLogic operates design studios and engineering centers around the world, extending our deep expertise to customers in the automotive, communications, financial services, healthcare and life sciences, manufacturing, media and entertainment, semiconductor, and technology industries.
GlobalLogic is a Hitachi Group Company operating under Hitachi, Ltd. (TSE: 6501) which contributes to a sustainable society with a higher quality of life by driving innovation through data and technology as the Social Innovation Business.
Visit our website at globallogic.com.
How Can We Help You?
Let's explore how the right digital engineering partner can help transform your business. Get in touch to book your free 15-minute initial consultation now.