Loading Strategies
How and when micro frontends load directly impacts perceived performance. A monolithic app loads everything upfront; micro frontends can load incrementally—but only if you design for it. This guide covers lazy loading, preloading, prefetching, progressive patterns, and how to minimize the cost of JavaScript in distributed frontends.
Lazy Loading Micro Frontends
Section titled “Lazy Loading Micro Frontends”Lazy loading means loading a micro frontend only when it is needed—typically when the user navigates to a route that renders it. Instead of bundling all MFs into the initial load, each MF is fetched on demand.
How It Works
Section titled “How It Works”- The shell (host application) loads first with minimal JS—routing logic and placeholders.
- When the user navigates to a route, the shell identifies the required MF(s).
- The MF bundle is fetched via dynamic
import()or a script loader. - The MF mounts and renders in its designated slot.
Benefits
Section titled “Benefits”- Smaller initial payload: Users download only what they need for the current view.
- Faster Time to Interactive (TTI): Less JavaScript to parse and compile upfront.
- Independent deployment: Each MF can be deployed and cached separately.
Considerations
Section titled “Considerations”- Navigation delay: The first visit to a route may show a loading state while the MF downloads. Mitigate with prefetching (see below).
- Waterfalls: Sequential loading (shell → route → MF) can create latency. Preload critical MFs or use link hints.
For bundle-level optimization that complements lazy loading, see Optimization Techniques.
Preloading and Prefetching
Section titled “Preloading and Prefetching”Preloading fetches resources before they are strictly needed, reducing perceived latency when the user navigates.
Prefetching MF Bundles on Hover or Proximity
Section titled “Prefetching MF Bundles on Hover or Proximity”When the user hovers over a link (or when a link enters the viewport), prefetch the target MF bundle. By the time they click, the bundle may already be cached.
Implementation:
<!-- Prefetch on hover (requires JS) --><a href="/checkout" data-prefetch="checkout-mf">Checkout</a>document.querySelectorAll('[data-prefetch]').forEach((link) => { link.addEventListener('mouseenter', () => { const mf = link.dataset.prefetch; import(/* webpackChunkName: "checkout" */ `./mfs/${mf}`); });});Or use <link rel="prefetch"> to hint the browser to fetch the resource at low priority.
Preloading Critical MFs
Section titled “Preloading Critical MFs”If certain MFs are highly likely to be needed (e.g., the cart widget on an e-commerce site), preload them after the shell is interactive. Use <link rel="modulepreload"> for ES modules or dynamic import() after the main thread is idle.
Speculative Loading Based on User Behavior
Section titled “Speculative Loading Based on User Behavior”Use analytics or heuristics to predict navigation:
- Users who view a product often go to checkout → prefetch checkout MF.
- Users on the dashboard often click “Settings” → prefetch settings MF.
Implement with requestIdleCallback or after LCP to avoid competing with critical resources.
Progressive Loading Patterns
Section titled “Progressive Loading Patterns”Progressive loading delivers content in stages, prioritizing what the user sees first.
Load the Shell First, Then MFs Incrementally
Section titled “Load the Shell First, Then MFs Incrementally”- Shell: Minimal HTML, CSS, routing, and layout. Renders quickly.
- Above-the-fold MF: The MF that fills the main content area for the initial route. Load it next.
- Secondary MFs: Header cart, sidebar, footer—load after the primary content is interactive.
- Below-the-fold MFs: Defer until the user scrolls or interacts.
Priority-Based Loading (Above-the-Fold First)
Section titled “Priority-Based Loading (Above-the-Fold First)”Define a priority order:
- P0: Shell, critical CSS, first-view MF
- P1: Navigation, cart widget, user menu
- P2: Footer, analytics, non-critical MFs
Use resource hints (preload, prefetch, modulepreload) and orchestration logic to enforce order. For how composition strategies affect loading, see Composition Strategies.
Skeleton Screens and Loading States
Section titled “Skeleton Screens and Loading States”When an MF is loading, show a skeleton or placeholder instead of a blank area. This improves perceived performance and reduces layout shift (CLS).
Best Practices
Section titled “Best Practices”- Reserve space for the MF’s approximate dimensions to avoid CLS.
- Use skeletons that match the final layout (cards, lists, etc.).
- Consider server-rendered skeletons for critical content.
- Provide accessible loading indicators for screen readers.
Skeletons are especially important when MFs load asynchronously and inject content into the DOM.
Streaming Server-Side Rendering with Micro Frontends
Section titled “Streaming Server-Side Rendering with Micro Frontends”SSR can improve LCP and SEO by rendering HTML on the server. With micro frontends, streaming SSR is possible: the shell streams first, then each MF streams as its data and markup become available.
How It Works
Section titled “How It Works”- Shell HTML streams to the client.
- Each MF is rendered on the server (or at the edge) and streamed into its slot.
- Hydration happens per-MF as chunks arrive.
Challenges
Section titled “Challenges”- Data boundaries: Each MF may need its own data-fetching; avoid waterfalls.
- Composition: Server-side composition requires a shell that can invoke MF renderers (e.g., via module federation, server components, or edge functions).
Streaming SSR is more complex than client-side composition but can yield better Core Web Vitals for content-heavy pages.
The Cost of JavaScript: Minimizing Parse and Compile Time
Section titled “The Cost of JavaScript: Minimizing Parse and Compile Time”JavaScript must be downloaded, parsed, and compiled before it runs. Large bundles delay interactivity. In micro frontends, multiple MF bundles add up.
Strategies
Section titled “Strategies”- Reduce total JS: Eliminate duplicates, tree-shake, and code-split aggressively. See Optimization Techniques for details.
- Defer non-critical JS: Load below-the-fold MFs after the main content is interactive.
- Use modern syntax: Transpile to modern targets to reduce parse time; avoid heavy polyfills when not needed.
- Avoid duplicate frameworks: Share React, Vue, or Angular across MFs so the framework is parsed once. See Shared Dependencies.
Measurement
Section titled “Measurement”Use Chrome DevTools Performance panel to profile parse/compile time. Long tasks (main thread blocked) often correlate with large JS. Aim for smaller, incremental chunks rather than one large bundle.
Real-World Loading Patterns: How Large Organizations Optimize
Section titled “Real-World Loading Patterns: How Large Organizations Optimize”Pattern 1: Shell + Route-Based MF Loading
Section titled “Pattern 1: Shell + Route-Based MF Loading”The shell loads with routing. Each route maps to an MF. On navigation, the MF is lazy-loaded. Prefetch on link hover for high-traffic routes.
Pattern 2: Critical Path Preload
Section titled “Pattern 2: Critical Path Preload”Identify the most common user journey (e.g., homepage → product → cart). Preload the product and cart MFs after the homepage MF is interactive.
Pattern 3: Edge-Deployed MFs
Section titled “Pattern 3: Edge-Deployed MFs”Deploy MF entry points at the CDN edge. Reduces latency for users globally. Combine with aggressive caching and content hashing.
Pattern 4: Gradual Hydration
Section titled “Pattern 4: Gradual Hydration”Stream HTML, then hydrate MFs progressively as they enter the viewport. Reduces initial main-thread work.
These patterns build on the techniques in Optimization Techniques—optimize bundles first, then optimize loading order and prefetching.
Summary
Section titled “Summary”Lazy loading keeps the initial payload small; preloading and prefetching reduce navigation delay. Progressive loading prioritizes above-the-fold content. Skeleton screens improve perceived performance and limit CLS. Streaming SSR can improve LCP for content-heavy apps. Minimize parse/compile time by reducing duplicate JS and sharing dependencies. Large organizations combine these patterns—route-based loading, critical-path preload, edge deployment, and gradual hydration—to deliver fast micro frontend experiences.
Go Deeper in the Book
This topic is covered in depth in Chapter 9 of Micro Frontends Architecture for Scalable Applications, with detailed examples, diagrams, and production-ready patterns.