effidevFlutter · Cloudflare edge · Cloud cost optimization
English

Building React Micro-Frontends with Vite + Module Federation and Independent CI/CD Pipelines

Vite + Module Federation React Micro-frontends Architecture

As engineering teams scale, monolithic frontend applications face severe bottlenecks: exponentially growing build times, frequent code merge conflicts, and high blast radiuses where a single broken release crashes the entire web application. To address these issues, Micro-Frontends adapt the principles of microservices architecture to client-side applications.

While Webpack 5 pioneered Module Federation, modern developers leverage Vite alongside Module Federation 2.0 (@originjs/plugin-module-federation or @module-federation/vite) to achieve fast HMR, ESM-native builds, and runtime module sharing.

This article details how to architect a React Micro-Frontend with Vite, manage shared singleton dependencies, handle runtime errors, and deploy independent pipelines via Cloudflare Pages and GitHub Actions.

Key Takeaways

  • Core Value of Module Federation: Remote modules are fetched at runtime instead of build time, allowing micro-apps to be built and deployed completely independently without rebuilding the Shell host.
  • Vite Runtime Sharing: Critical common libraries like react and react-dom are declared as shared singletons to avoid duplicate bundle downloads and memory footprint overhead.
  • Independent CI/CD: Remote application updates require zero modifications to the Host application. Updating the remote remoteEntry.js script allows instant zero-downtime and canary deployments.
  • Error Isolation: Placing React ErrorBoundary boundaries around dynamically loaded Remote components prevents isolated micro-app failures from breaking the overall Host Shell.

1. Micro-Frontend Architecture Overview

The system consists of a Host (Shell) App providing global routing, authentication, and layout, and multiple Remote Apps hosting domain-specific micro-applications.

+------------------------------------------------------------------+
|                        Host App (Shell)                          |
|  - Layout Header / Sidebar                                      |
|  - Auth State / Router Core                                      |
|                                                                  |
|   +--------------------------+    +--------------------------+   |
|   | Payment Remote (App 1)   |    | Product Remote (App 2)   |   |
|   | https://pay.domain.com   |    | https://prod.domain.com  |   |
|   | /remoteEntry.js          |    | /remoteEntry.js          |   |
|   +--------------------------+    +--------------------------+   |
+------------------------------------------------------------------+

2. Configuring Remote App (vite.config.ts)

// remote-payment/vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import federation from '@originjs/plugin-module-federation';

export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'paymentApp',
      filename: 'remoteEntry.js',
      exposes: {
        './CheckoutForm': './src/components/CheckoutForm.tsx',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.0.0 || ^19.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0 || ^19.0.0' },
      },
    }),
  ],
  build: {
    target: 'esnext',
  },
});

3. Host App Integration with Error Boundaries

// host-shell/src/pages/CheckoutPage.tsx
import React, { Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';

const RemoteCheckoutForm = React.lazy(() => import('paymentApp/CheckoutForm'));

export function CheckoutPage() {
  return (
    <div className="max-w-xl mx-auto p-6 space-y-4">
      <h1 className="text-2xl font-bold">Checkout</h1>
      <ErrorBoundary fallback={<div className="text-red-500">Failed to load payment module.</div>}>
        <Suspense fallback={<div>Loading remote form...</div>}>
          <RemoteCheckoutForm orderId="ORD-2026-9901" amount={45000} />
        </Suspense>
      </ErrorBoundary>
    </div>
  );
}

4. Architecture Comparison

Feature Monolith Iframe Strategy Vite Module Federation
Independent Build No Yes Yes
React Singleton Guaranteed Broken (Dual Load) Guaranteed via shared
Initial Load Heavy Monolith Bundle Slower Iframe Overhead Lazy-loaded on demand
CI/CD Build Time 10-20 min 2-3 min < 1 min per Remote