July 18, 2024 - 6 min
How Microfrontends Enhance our Digital Solutions
![Microfrontend blog hero image](https://q-web-production-s3bucket.s3.eu-central-1.amazonaws.com/wp-content/uploads/2024/07/18121938/q-blog-microfontends-02.jpg)
Q Pioneers Microfrontend Architecture for Large-Scale Projects
Q has successfully integrated microfrontend architecture into its development processes, showcasing this innovative approach in a major project for a prominent client in the Middle East. This project, serving over 12 million users, demonstrates the substantial benefits of microfrontends in modern digital solutions.
What are Microfrontends?
Microfrontends represent an architectural style where a web application is divided into smaller, more manageable fragments, each owned by different teams. Inspired by the microservices model used in backend development, microfrontends allow for independent deployment, updates, and scaling of distinct parts of an application. A prime example of this technology in action is Spotify, which utilizes microfrontends to streamline its platform’s user experience.
Advantages for Users and Developers
For End-Users:
- Frequent Updates
Each application segment can be updated independently, meaning faster bug fixes and feature enhancements without needing to rebuild the entire app. - Dynamic Experience
This leads to a more responsive and engaging user experience.
For Developers:
- Modular Development
Applications are broken down into smaller, manageable pieces, simplifying development and maintenance. - Enhanced Collaboration
The modularity accelerates workflows and reduces complexity, enhancing collaboration among development teams.
Tools and Processes in Microfrontend Development
Micro frontend developers typically work with a range of tools including:
- Webpack 5 for module bundling and module federation
- Module Federation allows applications to dynamically import remote modules (our microfrontends)
- FE JS framework for building components
- Docker for containerization and deployment
- CI/CD pipelines for continuous integration and delivery
The development process begins with a detailed brief outlining the project requirements. This is followed by designing the architecture, where the application is divided into distinct, autonomous fragments. Each team develops their segment independently, ensuring it integrates seamlessly with others. Rigorous testing and iterative refinements lead to the final solution, providing a cohesive user experience despite the segmented approach.
Challenges and Solutions
While microfrontends offer significant flexibility and speed, they also introduce challenges, particularly in maintaining a cohesive design and ensuring system security. However, with robust design systems and stringent security protocols, these challenges are effectively managed. The division into smaller elements does not inherently introduce more vulnerabilities; rather, it allows for targeted security measures, enhancing overall system resilience.
Cost Implications
From a cost perspective, microfrontend solutions can be more economical in the long run. The modular approach reduces development time and resources required for maintenance and updates. While the initial setup may be slightly more complex, the efficiency gains and reduced downtime translate to cost savings for users.
Conclusion
Q’s implementation of microfrontend architecture in large-scale projects underscores the technology’s potential to revolutionize digital solutions. By enabling rapid updates, enhancing developer productivity, and maintaining system security, microfrontends represent a forward-thinking approach to web application development. As more companies recognize these benefits, microfrontends are poised to become a standard in the industry.
How Q implements Microfrontends
By decomposing our interface into distinct microfrontends, we efficiently manage key UI layout components such as the header, sidebar, footer etc.. Each microfrontend is independently developed, deployed, and maintained, ensuring a high level of flexibility and rapid iteration. Our independent services then seamlessly integrate these microfrontends using advanced lazy loading techniques; this approach not only optimizes performance but also allows us to deliver a cohesive and consistently high-quality user experience across all our digital platforms.
Microapp Pattern
Additionally, we adopt the microapp pattern, where each significant section of the application is treated as a standalone app. This approach allows teams to work on different features independently, further enhancing scalability and maintainability. By leveraging the microapp pattern, we can deploy updates more frequently and ensure that each part of the application can evolve without affecting others.
Practical Implementation
Initial Release:
- All component implementations were housed within our core library
- Any changes to these components caused a version bump
Evolution of Core library to v2:
- Components’ implementation was relocated to a dedicated project (we’ll call it “Microfrontend Components”)
- v2 exclusively exports wrappers for those components, enabling developers to integrate microfrontends without extensive project rewrites
How Does It All Come Together?
- React UI Library
Our design system library - React Core Library
Fundamental library providing the core functionalities for the rest of our apps - React Starter
This acts as the starting point or boilerplate for new services. It includes the basic setup and configuration - Service
Standalone React service - Microfrontends
Self-contained frontend modules
Below is a diagram of how that looks in practice:
Examples
Below are example component diagrams and an example of implementation of our PublicFooter microfrontend.
Component Diagram
Code Example
import { type FC, lazy, Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
type PublicFooterProps = { /* props declaration for this component */ };
const PublicFooterLazy = lazy(
() => import('microfrontend_ref/PublicFooter')
);
export const PublicFooter: FC<PublicFooterProps> = (props) => (
<ErrorBoundary
FallbackComponent={
/*
error component to handle the logic in case the
chunk with micro frontend has failed to load
*/
}
>
<Suspense fallback={
/*
a skeleton to show while loading the chunk with micro frontend
*/
}>
<PublicFooterLazy {...props} />
/*
trigger the lazy import of the micro frontend chunk
*/
</Suspense>
</ErrorBoundary>
);
Webpack Module Federation
A powerful feature introduced in Webpack 5 that facilitates the integration and sharing of code between different applications. This approach is particularly beneficial for microfrontend architectures, where various parts of an application can be developed, deployed, and maintained independently.
Key Features and Benefits:
- Dynamic Importing of Remote Modules
Module Federation allows applications to dynamically import remote modules, enabling the seamless integration of our microfrontends. - Independent Deployment
Different parts of an application can be updated and deployed independently without requiring a complete rebuild or redeployment of the entire application. - Scalability and Maintainability
By allowing parts of the application to be independently updated and deployed, Module Federation enhances scalability and maintainability. Each microfrontend can be developed, tested, and deployed independently, allowing for better resource allocation and easier management of large-scale applications.
Webpack Config Example
import pkg from '../package.json';
const webpackRemoteConfig = (name, deps) => ({
name,
remotes: {
/*
Confirguration of microfrontend remotes
*/
},
shared: {
react: {
singleton: true,
eager: true,
requiredVersion: deps.react,
},
'react-dom': {
singleton: true,
requiredVersion: deps['react-dom'],
},
},
});
const exampleMicroFrontendPlugin =
new webpack.container.ModuleFederationPlugin(
webpackRemoteConfig(pkg.name, pkg.dependencies)
);
export default (mode) => ({
/*
Rest of your config
*/
plugins: [
exampleMicroFrontendPlugin,
],
});
Impact on the Bundle Size
After migrating to the microfrontends the bundle size of our code got smaller, because it no longer used some of the components from the core library. Unfortunately, the overall bundle size of the whole application will eventually be bigger since now this code is loaded from microfrontends and they have to have some code duplicated (such as design system, react-core, etc.) to ensure independence and separation of the microfrontends from the app that renders them.
After introducing microfrontends the whole bundle size of JavaScript files changed from 604kB to 722kB.
Solutions for the Client
This solution addresses several key challenges in modern large-scale web application development:
- Modularity and Scalability
Easier to manage and scale by breaking down the application into smaller self-contained microfrontends. - Performance Optimization
Lazy loading of microfrontends ensures that only the necessary parts of the application are loaded when needed. This reduces the initial load time and improves the overall performance of the application. - Maintainability
Isolating different parts of the application into separate microfrontends simplifies maintenance. Updates or bug fixes can be made to a specific component without affecting the rest of the application. This reduces the risk of introducing new issues and makes the codebase more manageable. - Flexibility and Reusability
Microfrontends can be reused across multiple projects or different parts of the same application. This promotes code reuse and reduces duplication, leading to more efficient development processes. - Technology Agnosticism
Different microfrontends can be built using different technologies or frameworks if needed. This allows teams to choose the best tools for each specific part of the application, enabling a more versatile and adaptable development environment. - Consistent User Experience
Despite being developed independently, microfrontends can be integrated seamlessly to provide a cohesive user experience. This ensures that users perceive the application as a unified whole rather than a collection of disparate components.
Project Case in Numbers
In this project we integrated 15+ government services (similiar to the Croatian government portal “e-gradani”) using microfrontend architecture within a period of six months. Each service reuses shared components and infrastructure, significantly enhancing efficiency and scalability.
Impact on Client’s Business
Q’s implementation of microfrontends has significantly impacted our client’s business by enabling faster development cycles, improved application performance, and reduced maintenance costs. This has lead to increased productivity and efficiency of our development teams. The consistent and high-quality user experience provided by our microfrontend architecture has also enhanced customer satisfaction and engagement. Furthermore, this approach has allowed our clients to swiftly adapt to market changes and demands, implement new features with ease, and maintain a competitive edge.
Give Kudos by sharing the post!