When to Adopt Micro Frontends: System Requirements, Design Guidelines, and Performance Tips
Adopt micro frontends when large, parallel development teams need independent releases, cross‑technology migration, or high‑frequency updates, and design them with a central app shell loading shared dependencies, choosing between iframe, web component, or lifecycle‑hook bundles, managing single‑ or multi‑instance routing, shared state or event‑bus communication, and optimizing performance through lazy rendering and shared library bundling.
Micro frontends, similar to micro‑services, have become a hot topic in recent years. As monolithic single‑page applications (SPAs) grow larger, the benefits of front‑end/back‑end separation—decoupled development and independent releases—diminish, and modular decomposition becomes necessary.
1. When does a system or front‑end team need micro frontends? The article lists several pain points that indicate a micro‑frontend approach could help:
Many modules need to be developed and released in parallel.
Large development teams (e.g., >10 developers) working on relatively independent sub‑modules.
Multiple teams collaborating on the same codebase, leading to coordination overhead.
High release frequency, typical of rapidly evolving business domains.
Cross‑technology‑stack migration, where legacy code coexists with newer frameworks.
These scenarios often result in complex dependency graphs and risky roll‑backs during releases.
2. Design points to consider when building a micro‑frontend architecture
Main module and sub‑modules
The main module (often called an APP Shell or Nutshell ) loads shared dependencies, initializes the entry point, and renders sub‑applications based on routing information. Sub‑applications can be implemented in three common ways:
As an iframe (simple but limited control).
As a Web Component (requires careful browser compatibility handling).
As an independently deployed JavaScript bundle exposing lifecycle hooks (register, mount, unmount) – the most widely used approach.
Single‑instance vs. multi‑instance
In a single‑instance model, only one sub‑module is active at a time, typically driven by routing. In a multi‑instance model, multiple sub‑modules can be active simultaneously, requiring more complex routing and layout management.
Example route configuration for a single‑instance setup:
const subAppRoutes = {
route1: 'https://your.static.server.com/app1/index.js',
route2: 'https://my.static.server.com/app2/index.js',
route3: 'https://other.static.server.com/app3/index.js'
};Example route configuration for a multi‑instance setup:
const subAppRoutes = {
route1: [
{ subApp: 'https://your.static.server.com/app1/index.js', layout: {/* layout info */} },
{ subApp: 'https://my.static.server.com/app2/index.js' }
],
route2: [
{ subApp: 'https://your.static.server.com/app2/index.js' },
{ subApp: 'https://my.static.server.com/app3/index.js' }
],
route3: [
{ subApp: 'https://my.static.server.com/app3/index.js' }
]
};The entry module must maintain a routing map and may need a dynamic schema to describe where each micro‑frontend should be placed, enabling low‑code assembly.
Sub‑module communication
Typical communication patterns include:
Global state sharing : a shared store where one module writes changes and others react, with namespace isolation to avoid conflicts.
Event bus : modules publish and subscribe to events. Care must be taken to handle the case where a consumer is not yet instantiated—event buffering may be required.
Both patterns are generally needed for robust micro‑frontend systems.
3. Performance optimization tips
On‑demand rendering for multi‑instance apps
When many sub‑modules exist on a page, render them lazily based on viewport visibility. This reduces initial scripting and resource load time, while pre‑rendering can be used during idle periods.
Duplicate bundling reduction
Common libraries (e.g., UI components, polyfills) should be shared rather than bundled into each sub‑module. Strategies include:
Providing shared capabilities from the entry module (e.g., global AJAX, telemetry).
Extracting common code into a shared bundle, such as polyfills, and loading them only once.
Using runtime polyfill services (e.g., polyfill.io) or Webpack 5 Module Federation (cautiously in production).
Maintaining a whitelist/blacklist for polyfills and enforcing compliance via development tooling.
These approaches help keep the overall bundle size low and improve load performance.
References
Micro Frontends – Martin Fowler: https://martinfowler.com/articles/micro-frontends.html#IncrementalUpgrades
@babel/preset‑env “usage” option: https://babeljs.io/docs/en/babel-preset-env#usebuiltins
Polyfill.io: http://polyfill.io/
Webpack Module Federation: https://webpack.js.org/concepts/module-federation/
Baidu Geek Talk
Follow us to discover more Baidu tech insights.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.