Frontend Development 22 min read

Micro Frontends: Concepts, Implementation Strategies, and Technical Details

Micro frontends decompose large monolithic front‑end applications into independent, technology‑agnostic sub‑apps, detailing their background, advantages, suitable scenarios, and various implementation approaches—including MPA, server‑side composition, build‑time and runtime composition with module federation, iframe, JS sandbox, CSS isolation, and routing techniques.

ByteFE
ByteFE
ByteFE
Micro Frontends: Concepts, Implementation Strategies, and Technical Details

Background

Monolithic Frontend Application (Giant Stone)

Modern frontend applications are becoming increasingly feature‑rich and interactive. Behind a complex monolithic frontend lies a massive micro‑service cluster of backend services. As a single team maintains a frontend project over time, it grows larger and harder to maintain, so we refer to such an application as a "Giant Stone" monolithic frontend.

Frontend‑Backend Collaboration

Backend development has evolved from mixed front‑back development to separation and now to micro‑service decomposition. After splitting by domain, backend services become clearer and easier to maintain.

Micro‑frontend adopts the micro‑service architectural idea, discarding large monolithic approaches and breaking the frontend into small, simple blocks that can be developed, tested, and deployed independently while still being aggregated into a single product for the user.

What is Micro‑Frontend

In short: Micro‑frontend is an architectural style that composes independently delivered frontend applications into a larger whole, improving development experience while preserving product experience.

Common implementation patterns load sub‑apps via a loader in the main app, use a router to decide loading timing, and a store for cross‑app data sharing, making the split invisible to users.

Advantages

Technology‑stack agnostic: the main framework does not restrict the stack of sub‑apps.

Independent development and deployment: each team has its own repository and can deploy without affecting others.

Runtime isolation: state is isolated between sub‑apps.

Incremental upgrades: large applications can be upgraded gradually via micro‑apps.

Applicable Scenarios

Legacy system compatibility: add new features as separate micro‑apps, choosing any stack.

Application aggregation: provide a unified entry page that aggregates multiple apps.

Cross‑team development: eliminate stack constraints and deployment conflicts.

Implementation Approaches

MPA (Multi‑Page Application)

Strictly speaking, MPA is not a standard micro‑frontend solution; users may experience page‑level fragmentation, similar to being told to buy vegetables at another store. A better approach would be to fetch the missing item for the user instantly, avoiding the extra navigation steps.

Divide the system into multiple repositories and aggregate entry points or a unified navigation component on the homepage using the MPA pattern.

The navigation records the entry URLs of all sub‑apps; clicking an entry redirects to the corresponding sub‑platform. The common navigation component should be extracted for reuse.

Drawbacks of MPA in micro‑frontend scenarios:

Only page‑level splitting, not component‑level.

User experience is fragmented; navigation between pages cannot achieve SPA‑like smoothness.

Different systems cannot communicate directly.

Updating shared parts requires coordinated operations across teams.

Server‑Side Composition

Before modern bundlers, developers used template engines like hbs or ejs to compose static HTML fragments on the server based on request paths.

Assuming an index.html contains common page elements, server‑side includes insert page‑specific fragments, resulting in a complete page structure.

Thus, micro‑frontend concepts do not necessarily require new technologies.

Build‑Time Composition

npm

Package each sub‑app as an npm package and import it as a dependency in the main app.

Drawbacks:

High cost of converting sub‑apps into npm packages.

Maintenance becomes cumbersome; each version bump requires republishing the main app.

Duplicate inclusion of shared dependencies across sub‑apps.

Module Federation

Webpack 5's Module Federation enables publishing modules that consumers can consume in real time, as well as build‑time optimizations. One app can directly import modules from another.

EMP

EMP is a micro‑frontend framework based on Module Federation. Each micro‑app imports shared modules via remote calls, reducing duplicate bundle size and speeding up builds.

EMP solves dynamic updates but still requires handling JS sandboxing, CSS isolation, and is more suited for micro‑components than full micro‑apps.

Runtime Composition

iframe

Embedding sub‑apps via iframe offers strong isolation of styles and global variables, but the isolation prevents context sharing, leading to poor developer and user experience.

Drawbacks of iframe in micro‑frontend scenarios:

URL synchronization loss on refresh; back/forward buttons break.

UI cannot share DOM; e.g., full‑page modals are impossible.

Global context is completely isolated; data sharing and single‑sign‑on become difficult.

Each navigation incurs a full page reload, slowing loading.

🤔 Is there a way to keep iframe advantages while solving its pain points? See below.

JS Loading Sub‑Apps

Loading sub‑apps via JavaScript is the most flexible and widely used method. Each sub‑app exposes lifecycle hooks (bootstrap, mount, unmount) on the window object; the main app decides which sub‑app to render and calls the appropriate hook.

Qiankun

Based on single‑spa , Qiankun registers sub‑apps with entry URLs, active routes, and namespaces. Sub‑apps must expose the three lifecycle hooks for the container to invoke.

Two JS sandbox solutions are provided:

Snapshot mode: record global state before loading a sub‑app and restore it on unload (for environments without Proxy ).

Proxy mode: intercept window operations, create a fakeWindow , and delegate reads/writes accordingly.

CSS isolation is achieved by prefixing each rule, e.g., p{color:#000} becomes .app1 p{color:#000} .

Qiankun is mature and widely adopted, but it still requires some adaptation of sub‑apps (UMD packaging, exposing hooks).

Wujie

Wujie implements JS sandboxing with iframe and uses WebComponent for CSS isolation.

It dynamically loads sub‑app resources, creates a shadowDOM node and an iframe, injects JS into the iframe, and places DOM/CSS into the shadowDOM. It also hijacks iframe 's history.pushState and history.replaceState to sync URLs with the main app.

WebComponent

Instead of requiring global functions, sub‑apps are wrapped as custom HTML elements. ShadowDOM provides strong style isolation.

micro‑app

micro‑app adopts the WebComponent idea, using CustomElement with a custom ShadowDom . It does not require sub‑apps to modify rendering logic or expose hooks, and does not need webpack configuration changes, resulting in low integration cost.

Note: ShadowDOM compatibility with React (especially versions ≤16) can be problematic because synthetic events may not fire inside shadow roots.

Technical Details

The technical details below mainly reference Qiankun; other frameworks have similar concepts.

Route Hijacking

Single‑page apps use either hash or history routing. Both require listening to popstate and hashchange , and also need to override pushState and replaceState because they change the URL without emitting events.

Rendering Sub‑Apps

Loading a sub‑app starts with fetching its entry resource. Two entry strategies exist:

JS Entry – bundle the whole micro‑app into a single JS file (high conversion cost, loses on‑demand loading and CSS splitting).

HTML Entry – use import-html-entry to fetch the HTML, parse it into template , scripts , styles , and entry .

{
  template: /* processed DOM with script/link tags removed */,
  scripts: [/* script URLs or inline script objects */],
  styles: [/* stylesheet URLs */],
  entry: /* entry script URL */
}

The loading process of import-html-entry :

Fetch the HTML content.

Resolve relative resource URLs and extract link and script tags.

Return the transformed template together with loaded JS and CSS.

JS Sandbox

Snapshot mode – record global state before loading a sub‑app and restore it on unload.

Proxy mode – use Proxy (or Object.defineProperty ) to intercept window accesses, routing reads/writes through a fakeWindow object.

CSS Isolation

Dynamic Stylesheet – insert and remove style nodes when a sub‑app mounts/unmounts, ensuring only one app's styles are active at a time.

Compilation transformation – a PostCSS plugin adds a unique prefix to every rule during build.

Domain isolation – prepend a specific selector (e.g., .app1 ) to each rule.

Implementation steps for domain isolation:

Create a temporary style node.

Iterate over its sheet.cssRules collection.

Apply a regex‑based transformation to each rule.

Replace the original style node with the transformed one.

Conclusion

Future Directions

Current micro‑frontend frameworks still require some adaptation cost; component‑style references could lower this barrier.

Standardized sandbox capabilities from the W3C could unify the disparate sandbox implementations.

Reducing technical constraints (e.g., EMP's reliance on webpack, Qiankun's UMD packaging) will make frameworks more flexible.

Issues to Note

Extensive testing across many applications is needed to ensure a complete experience.

Debugging requires system‑wide visibility.

Version consistency across the whole ecosystem must be managed.

In summary, micro‑frontend solves collaborative front‑end development under a controllable system, addressing both spatial separation for teamwork and temporal continuity for upgrades.

References

[1] Webpack Module Federation

[2] Wujie Micro – Guide

[3] React ShadowDOM Issue

[4] Micro‑Frontend Implementation Article

[5] Qiankun CSS Sandbox Source

[6] Why Not Iframe – Yuque

[7] Enterprise‑Level Micro‑Frontend Framework Tutorial

[8] Micro Frontends – Martin Fowler

[9] MicroApp Documentation

[10] Qiankun Guide

module federationfrontend architectureJS Sandboxmicro frontendscss isolationruntime composition
ByteFE
Written by

ByteFE

Cutting‑edge tech, article sharing, and practical insights from the ByteDance frontend team.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.