Chandan9898Kumar/Micro-Apps

A comprehensive implementation of micro-frontend architecture using Webpack Module Federation, React, TypeScript, and Lerna for monorepo management.

โ˜… 1Forks 0TypeScriptGitHub โ†—Compare
microservices

README

๐Ÿš€ Micro-Frontend Architecture with Module Federation

A comprehensive implementation of micro-frontend architecture using Webpack Module Federation, React, TypeScript, and Lerna for monorepo management.

๐Ÿ“‹ Table of Contents

๐ŸŽฏ Overview

This project demonstrates a micro-frontend architecture where multiple independent React applications work together as a unified system. Each micro-frontend can be developed, tested, and deployed independently while sharing components and state seamlessly.

Key Features

  • โœ… Independent Development: Each app can be developed separately
  • โœ… Shared State Management: Global state synchronization across micro-frontends
  • โœ… Module Federation: Runtime component sharing without build-time dependencies
  • โœ… Monorepo Management: Unified development experience with Lerna
  • โœ… TypeScript Support: Full type safety across all applications
  • โœ… Hot Module Replacement: Fast development with instant updates

๐Ÿ—๏ธ Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    CONTAINER APP (Port 3000)                โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”‚
โ”‚  โ”‚   APP-1 Remote  โ”‚              โ”‚   APP-2 Remote  โ”‚       โ”‚
โ”‚  โ”‚  (Port 3001)    โ”‚              โ”‚  (Port 3002)    โ”‚       โ”‚
โ”‚  โ”‚                 โ”‚              โ”‚                 โ”‚       โ”‚
โ”‚  โ”‚ CounterAppOne   โ”‚              โ”‚ CounterAppTwo   โ”‚       โ”‚
โ”‚  โ”‚ Component       โ”‚              โ”‚ Component       โ”‚       โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ”‚
โ”‚                                                             โ”‚
โ”‚  Global State: window.globalMicroState                      โ”‚
โ”‚  { app1: number, app2: number }                             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Application Roles

Application Port Role Exposes Consumes
Container 3000 Host/Shell - CounterAppOne, CounterAppTwo
App1 3001 Remote CounterAppOne -
App2 3002 Remote CounterAppTwo -

๐Ÿ› ๏ธ Tech Stack

Core Technologies

  • React 17.0.2: Frontend library for building user interfaces
  • TypeScript 4.2.4: Type-safe JavaScript with static type checking
  • Webpack 5.67.0: Module bundler with Module Federation plugin
  • Lerna 3.22.1: Monorepo management tool

Development Tools

  • Webpack Dev Server: Development server with hot reloading
  • Babel: JavaScript transpiler for modern syntax support
  • Fork TS Checker: TypeScript type checking in separate process

Module Federation

  • Webpack Module Federation: Runtime code sharing between applications
  • Dynamic Imports: Lazy loading of remote components
  • Shared Dependencies: React and React-DOM shared as singletons

๐Ÿ“ Project Structure

Microfrontend-ModuleFederation-React-Lerna/
โ”œโ”€โ”€ ๐Ÿ“ฆ container/                 # Host application (Port 3000)
โ”‚   โ”œโ”€โ”€ src/
โ”‚   โ”‚   โ”œโ”€โ”€ App.tsx              # Main container component
โ”‚   โ”‚   โ”œโ”€โ”€ bootstrap.tsx        # App initialization
โ”‚   โ”‚   โ””โ”€โ”€ index.ts             # Entry point
โ”‚   โ”œโ”€โ”€ webpack.config.js        # Webpack configuration
โ”‚   โ””โ”€โ”€ package.json             # Dependencies & scripts
โ”‚
โ”œโ”€โ”€ ๐Ÿ“ฆ app1/                     # Remote application 1 (Port 3001)
โ”‚   โ”œโ”€โ”€ src/
โ”‚   โ”‚   โ”œโ”€โ”€ components/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ CounterAppOne.tsx # Exposed component
โ”‚   โ”‚   โ”œโ”€โ”€ App.tsx              # Standalone app
โ”‚   โ”‚   โ””โ”€โ”€ index.ts             # Entry point
โ”‚   โ”œโ”€โ”€ webpack.config.js        # Module Federation config
โ”‚   โ””โ”€โ”€ package.json             # Dependencies & scripts
โ”‚
โ”œโ”€โ”€ ๐Ÿ“ฆ app2/                     # Remote application 2 (Port 3002)
โ”‚   โ”œโ”€โ”€ src/
โ”‚   โ”‚   โ”œโ”€โ”€ components/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ CounterAppTwo.tsx # Exposed component
โ”‚   โ”‚   โ”œโ”€โ”€ App.tsx              # Standalone app
โ”‚   โ”‚   โ””โ”€โ”€ index.ts             # Entry point
โ”‚   โ”œโ”€โ”€ webpack.config.js        # Module Federation config
โ”‚   โ””โ”€โ”€ package.json             # Dependencies & scripts
โ”‚
โ”œโ”€โ”€ ๐Ÿ“„ lerna.json               # Lerna configuration
โ”œโ”€โ”€ ๐Ÿ“„ package.json             # Root package.json
โ””โ”€โ”€ ๐Ÿ“„ README.md                # This file

๐Ÿ”„ Data Sharing Strategy

Global State Management

The application uses a global window object approach for cross-micro-frontend state sharing:

// Global state interface
interface GlobalState {
  app1: number;  // Counter value for App1
  app2: number;  // Counter value for App2
}

// Initialize global state
if (!window.globalMicroState) {
  window.globalMicroState = { app1: 0, app2: 1 };
}

State Synchronization Process

  1. Initialization: Each component reads initial state from window.globalMicroState
  2. Updates: When a user clicks a button, the component:
    • Updates local React state
    • Updates global window state
    • Triggers re-render in all listening components
  3. Polling: Components poll global state every 100ms to detect changes
  4. Real-time Sync: Changes in one micro-frontend instantly reflect in others

Why This Approach?

Approach Pros Cons Used?
localStorage Persistent Domain-specific (localhost:3000 โ‰  localhost:3001) โŒ
postMessage Cross-origin Complex setup, iframe-based โŒ
URL Parameters Shareable Manual copying required โŒ
Global Window Simple, same context Only works in Module Federation โœ…

๐Ÿ“š Lerna Monorepo Management

What is Lerna?

Lerna is a tool for managing JavaScript projects with multiple packages (monorepo). It optimizes the workflow around managing multi-package repositories.

Why We Need Lerna

Without Lerna (Problems):

# You'd need to run each app separately
cd container && npm start &
cd app1 && npm start &
cd app2 && npm start &

With Lerna (Solution):

# Single command starts all apps
npm start  # Runs all 3 apps in parallel

How Lerna Works

  1. Dependency Management:

    • Hoists common dependencies to root
    • Reduces duplicate installations
    • Manages inter-package dependencies
  2. Script Orchestration:

    {
      "scripts": {
        "start": "lerna run --parallel start",
        "build": "lerna run build",
        "clean": "lerna run --parallel clean"
      }
    }
  3. Workspace Configuration:

    {
      "workspaces": {
        "packages": ["app1", "app2", "container"]
      }
    }

Lerna Commands

Command Description Usage
lerna bootstrap Install dependencies for all packages Initial setup
lerna run start Run start script in all packages Development
lerna run --parallel start Run start scripts in parallel Faster development
lerna clean Remove node_modules from all packages Cleanup
lerna version Version all packages Release management

โš™๏ธ Setup & Installation

Prerequisites

  • Node.js: Version 14+
  • npm: Version 6+
  • Git: For version control

Installation Steps

  1. Clone the Repository

    git clone https://github.com/Chandan9898Kumar/Micro-Apps.git
    cd Microfrontend-ModuleFederation-React-Lerna
  2. Install Root Dependencies

    npm install

    This installs Lerna and sets up the monorepo structure.

  3. Bootstrap All Packages (Optional - Lerna handles this automatically)

    npx lerna bootstrap
  4. Verify Installation

    npx lerna list

    Should show: container, app1, app2

๐Ÿš€ Running the Project

Option 1: Start All Applications (Recommended)

npm start

This command:

  • Starts all 3 applications in parallel
  • Opens browser automatically
  • Enables hot module replacement

Access URLs:

Option 2: Start Individual Applications

# Terminal 1 - Container
cd container && npm start

# Terminal 2 - App1  
cd app1 && npm start

# Terminal 3 - App2
cd app2 && npm start

Option 3: Development Commands

# Build all applications
npm run build

# Clean all node_modules
npm run clean

# Serve built applications
npm run serve

๐Ÿ”ง How It Works

Module Federation Configuration

Container (Host) Configuration:

new ModuleFederationPlugin({
  name: "container",
  remotes: {
    app1: "app1@http://localhost:3001/remoteEntry.js",
    app2: "app2@http://localhost:3002/remoteEntry.js",
  },
  shared: {
    react: { singleton: true },
    "react-dom": { singleton: true },
  },
})

Remote App Configuration:

new ModuleFederationPlugin({
  name: "app1",
  filename: "remoteEntry.js",
  exposes: {
    "./CounterAppOne": "./src/components/CounterAppOne",
  },
  shared: {
    react: { singleton: true },
    "react-dom": { singleton: true },
  },
})

Component Loading Process

  1. Container Starts: Loads at http://localhost:3000
  2. Dynamic Imports: Container dynamically imports remote components:
    const CounterAppOne = React.lazy(() => import("app1/CounterAppOne"));
    const CounterAppTwo = React.lazy(() => import("app2/CounterAppTwo"));
  3. Runtime Resolution: Webpack fetches components from remote URLs
  4. Shared Dependencies: React/ReactDOM shared as singletons
  5. State Synchronization: Global state keeps all components in sync

State Flow Diagram

User clicks button in Container
         โ†“
Local state updates (setCount)
         โ†“
Global state updates (window.globalMicroState)
         โ†“
Polling detects change (100ms interval)
         โ†“
All components re-render with new state
         โ†“
UI updates across all micro-frontends

๐Ÿ”„ Development Workflow

Adding a New Micro-Frontend

  1. Create New Package:

    mkdir app3
    cd app3
    npm init -y
  2. Add to Lerna Workspaces:

    // Root package.json
    {
      "workspaces": {
        "packages": ["app1", "app2", "container", "app3"]
      }
    }
  3. Configure Module Federation:

    // app3/webpack.config.js
    new ModuleFederationPlugin({
      name: "app3",
      filename: "remoteEntry.js",
      exposes: {
        "./CounterAppThree": "./src/components/CounterAppThree",
      },
    })
  4. Update Container:

    // container/webpack.config.js
    remotes: {
      app1: "app1@http://localhost:3001/remoteEntry.js",
      app2: "app2@http://localhost:3002/remoteEntry.js",
      app3: "app3@http://localhost:3003/remoteEntry.js", // Add this
    }

Best Practices

  1. State Management: Use global state for shared data, local state for component-specific data
  2. Error Boundaries: Wrap remote components in error boundaries
  3. Loading States: Always provide fallback components for lazy-loaded remotes
  4. Type Safety: Share TypeScript interfaces between micro-frontends
  5. Testing: Test each micro-frontend independently and integration scenarios

๐Ÿ› Troubleshooting

Common Issues & Solutions

1. "webpack is not recognized"

Problem: Missing webpack installation

# Solution
npm install  # Install root dependencies first

2. "Module not found: Can't resolve 'app1/CounterAppOne'"

Problem: Remote application not running

# Solution
npm start  # Ensure all apps are running

3. "Uncaught ChunkLoadError"

Problem: Remote entry point not accessible

# Check if remotes are running:
curl http://localhost:3001/remoteEntry.js
curl http://localhost:3002/remoteEntry.js

4. State not syncing between apps

Problem: Global state not initialized

// Solution: Ensure global state is initialized in each component
if (!window.globalMicroState) {
  window.globalMicroState = { app1: 0, app2: 1 };
}

5. "lerna: command not found"

Problem: Lerna not installed globally

# Solution 1: Install globally
npm install -g lerna

# Solution 2: Use npx
npx lerna bootstrap

Performance Optimization

  1. Shared Dependencies: Ensure React is shared as singleton
  2. Code Splitting: Use React.lazy for remote components
  3. Caching: Configure webpack caching for faster builds
  4. Bundle Analysis: Use webpack-bundle-analyzer to optimize bundles

Debugging Tips

  1. Network Tab: Check if remote entries are loading correctly
  2. Console Logs: Add logging to track state changes
  3. React DevTools: Debug component state and props
  4. Webpack Stats: Analyze bundle composition and dependencies

๐Ÿ“ˆ Production Considerations

Deployment Strategy

  1. Independent Deployment: Each micro-frontend can be deployed separately
  2. CDN Distribution: Host remote entries on CDN for better performance
  3. Version Management: Use semantic versioning for micro-frontend releases
  4. Rollback Strategy: Maintain multiple versions for quick rollbacks

Security

  1. CORS Configuration: Properly configure cross-origin requests
  2. Content Security Policy: Set appropriate CSP headers
  3. Dependency Scanning: Regular security audits of dependencies

Monitoring

  1. Error Tracking: Monitor micro-frontend errors separately
  2. Performance Metrics: Track loading times and bundle sizes
  3. User Analytics: Measure user interactions across micro-frontends

๐Ÿค Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/new-feature
  3. Commit changes: git commit -am 'Add new feature'
  4. Push to branch: git push origin feature/new-feature
  5. Submit a Pull Request

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ™ Acknowledgments


Happy Coding! ๐Ÿš€

Contributors

Chandan9898KumarPavanAditya

Issues