Skip to content

TechOctopus/ecommerce-app-monorepo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Micro-frontend architecture for ecommerce application

Overview

The project demonstrates three different approaches to organizing a frontend application:

  1. Monolithic application - traditional approach with a single codebase
  2. Runtime micro-frontend integration - using Module Federation to load modules at runtime
  3. Build-time micro-frontend integration - bundling all modules together at build time

Links Table

Version Link (development) Link (production)
Ecommerce Monolith http://localhost:3010/ http://localhost:9001/
Ecommerce MF Runtime Integration http://localhost:3100/ http://localhost:9002/
Ecommerce MF Build Integration http://localhost:3200/ http://localhost:9003/

1. Monolithic Application (Ecommerce Monolith)

Description

A traditional monolithic application where all components, sections, and logic are in a single codebase. The application is bundled as one bundle and deployed as a single unit.

Characteristics

  • Single codebase: All modules (Product, Checkout, Inspire) are in one repository
  • Single bundle: One JavaScript bundle is created during build
  • Shared dependencies: React and other dependencies are loaded once
  • Simple deployment: Only one application needs to be deployed
  • Tight coupling: All components have direct access to each other

Architecture Diagram

graph TB
    subgraph "Ecommerce Monolith App"
        Shell[Shell/App Component]
        ProductSection[Product Section]
        CheckoutSection[Checkout Section]
        InspireSection[Inspire Section]
        SharedContext[Shared Contexts<br/>Theme, Cart, Products]
    end

    subgraph "Dependencies"
        React[React & React-DOM]
        UICore[UI Core Components]
    end

    Shell --> ProductSection
    Shell --> CheckoutSection
    Shell --> InspireSection
    Shell --> SharedContext
    ProductSection --> SharedContext
    CheckoutSection --> SharedContext
    InspireSection --> SharedContext

    ProductSection --> React
    CheckoutSection --> React
    InspireSection --> React
    Shell --> React

    ProductSection --> UICore
    CheckoutSection --> UICore
    InspireSection --> UICore
Loading

Build and Deployment Diagram

graph LR
    A[Source Code] --> B[Webpack Build]
    B --> C[Single Bundle<br/>main.js]
    C --> D[Web Server<br/>Port 3010]
Loading

Advantages

  • ✅ Simple development and debugging
  • ✅ No dependency versioning issues
  • ✅ Bundle size optimization at the application level
  • ✅ Easy state sharing between components
  • ✅ Fast loading due to single bundle

Disadvantages

  • ❌ Requires deployment of entire application for changes in one section
  • ❌ Large codebase can slow down development
  • ❌ Resource monopolization by one team
  • ❌ Difficulty scaling teams

Project Structure

apps/ecommerce-monolith/
├── src/
│   ├── App.js              # Main application component
│   ├── sections/
│   │   ├── Product.js      # Product section
│   │   ├── Checkout.js     # Checkout section
│   │   └── Inspire.js      # Inspire section
│   └── context/
│       ├── ThemeContext.js
│       ├── CartContext.js
│       └── ProductsContext.js
└── webpack.config.js       # Build configuration

2. Runtime Micro-frontend Integration (Ecommerce MF Runtime Integration)

Description

Micro-frontend architecture using Webpack Module Federation to load remote modules at runtime. Each micro-frontend (Product, Checkout, Inspire) is built and deployed independently, and the Shell application loads them dynamically through remoteEntry.js files.

Characteristics

  • Independent applications: Each micro-frontend is a separate application with its own dev server
  • Dynamic loading: Modules are loaded at runtime via HTTP
  • Module Federation: Uses Webpack Module Federation Plugin
  • Shared dependencies: React and other dependencies are loaded once and used by all micro-frontends
  • Independent deployment: Each micro-frontend can be deployed separately

Architecture Diagram

graph TB
    subgraph "Browser"
        ShellApp[Shell App<br/>Port 3100]
        LazyLoad[React.lazy<br/>Dynamic Imports]
    end

    subgraph "Micro-frontends"
        ProductMF[Product MF<br/>Port 3101]
        CheckoutMF[Checkout MF<br/>Port 3102]
        InspireMF[Inspire MF<br/>Port 3103]
    end

    subgraph "Module Federation"
        ProductRemote[remoteEntry.js<br/>Product]
        CheckoutRemote[remoteEntry.js<br/>Checkout]
        InspireRemote[remoteEntry.js<br/>Inspire]
    end

    ShellApp --> LazyLoad
    LazyLoad --> ProductRemote
    LazyLoad --> CheckoutRemote
    LazyLoad --> InspireRemote

    ProductRemote -.HTTP.-> ProductMF
    CheckoutRemote -.HTTP.-> CheckoutMF
    InspireRemote -.HTTP.-> InspireMF

    ShellApp --> SharedReact[Shared React]
    ProductMF --> SharedReact
    CheckoutMF --> SharedReact
    InspireMF --> SharedReact
Loading

Build and Deployment Diagram

graph TB
    subgraph "Build Phase"
        A1[Shell Build] --> B1[Shell Bundle<br/>+ Remote Config]
        A2[Product Build] --> B2[Product Bundle<br/>+ remoteEntry.js]
        A3[Checkout Build] --> B3[Checkout Bundle<br/>+ remoteEntry.js]
        A4[Inspire Build] --> B4[Inspire Bundle<br/>+ remoteEntry.js]
    end

    subgraph "Deployment Phase"
        B1 --> D1[Web Server<br/>Port 3100]
        B2 --> D2[Web Server<br/>Port 3101]
        B3 --> D3[Web Server<br/>Port 3102]
        B4 --> D4[Web Server<br/>Port 3103]
    end

    subgraph "Runtime Phase"
        D1 --> Browser[Browser]
        Browser -.HTTP Request.-> D2
        Browser -.HTTP Request.-> D3
        Browser -.HTTP Request.-> D4
    end
Loading

Component Interaction Diagram

sequenceDiagram
    participant Browser
    participant Shell as Shell App (3100)
    participant Product as Product MF (3101)
    participant Checkout as Checkout MF (3102)
    participant Inspire as Inspire MF (3103)

    Browser->>Shell: Load application
    Shell->>Browser: Load Shell bundle

    Browser->>Shell: Request Product section
    Shell->>Product: Load remoteEntry.js
    Product-->>Browser: Transfer Product/Section

    Browser->>Shell: Request Checkout section
    Shell->>Checkout: Load remoteEntry.js
    Checkout-->>Browser: Transfer Checkout/Section

    Browser->>Shell: Request Inspire section
    Shell->>Inspire: Load remoteEntry.js
    Inspire-->>Browser: Transfer Inspire/Section
Loading

Module Federation Configuration

Shell (host):

remotes: {
  ecommerce_product: 'ecommerce_product@http://localhost:3101/remoteEntry.js',
  ecommerce_checkout: 'ecommerce_checkout@http://localhost:3102/remoteEntry.js',
  ecommerce_inspire: 'ecommerce_inspire@http://localhost:3103/remoteEntry.js',
}

Remote (exposes):

exposes: {
  './Section': './src/Section'
}

Advantages

  • ✅ Independent deployment of micro-frontends
  • ✅ Isolated teams can work independently
  • ✅ Flexibility in technology choice for each micro-frontend
  • ✅ On-demand module loading (lazy loading)
  • ✅ Ability to A/B test individual micro-frontends

Disadvantages

  • ❌ Difficulty debugging distributed modules
  • ❌ Potential issues with dependency versions
  • ❌ Additional HTTP requests for module loading
  • ❌ Requires coordination between teams for shared APIs
  • ❌ More complex CORS and security setup

Project Structure

apps/
├── ecommerce-mf-shell/      # Host application
│   ├── src/
│   │   └── bootstrap.js     # Dynamic imports via React.lazy
│   └── webpack.config.js    # Module Federation remotes
├── ecommerce-mf-product/    # Remote module
│   ├── src/
│   │   └── Section.js       # Exported component
│   └── webpack.config.js    # Module Federation exposes
├── ecommerce-mf-checkout/   # Remote module
└── ecommerce-mf-inspire/     # Remote module

3. Build-time Micro-frontend Integration (Ecommerce MF Build Integration)

Description

A hybrid approach where micro-frontends are developed as separate packages in a monorepo but bundled together with the Shell application at build time. Uses regular npm/yarn package imports instead of Module Federation.

Characteristics

  • Separate development: Each section is developed as a separate package
  • Bundled together: All packages are bundled into one bundle at build time
  • Regular imports: Uses standard ES6 imports instead of Module Federation
  • Monorepo: All packages are in one repository (Turborepo)
  • Single bundle: Build result is one JavaScript file

Architecture Diagram

graph TB
    subgraph "Monorepo Structure"
        Shell[Shell App<br/>Port 3200]

        subgraph "Packages"
            ProductPkg["@packages/ecommerce-sections-product"]
            CheckoutPkg["@packages/ecommerce-sections-checkout"]
            InspirePkg["@packages/ecommerce-sections-inspire"]
            UICore["@ui-core/web-components"]
        end
    end

    subgraph "Build Process"
        Webpack[Webpack Bundler]
        SingleBundle[Single Bundle<br/>main.js]
    end

    Shell --> ProductPkg
    Shell --> CheckoutPkg
    Shell --> InspirePkg

    ProductPkg --> UICore
    CheckoutPkg --> UICore
    InspirePkg --> UICore

    Shell --> Webpack
    ProductPkg --> Webpack
    CheckoutPkg --> Webpack
    InspirePkg --> Webpack
    UICore --> Webpack

    Webpack --> SingleBundle
Loading

Build and Deployment Diagram

graph TB
    subgraph "Development Phase"
        Dev1[Product Package<br/>Development]
        Dev2[Checkout Package<br/>Development]
        Dev3[Inspire Package<br/>Development]
    end

    subgraph "Build Phase"
        A[Shell App] --> B[Turborepo Build]
        Dev1 --> B
        Dev2 --> B
        Dev3 --> B
        B --> C[Webpack Bundle]
        C --> D[Single Bundle<br/>main.js]
    end

    subgraph "Deployment Phase"
        D --> E[Web Server<br/>Port 3200]
        E --> F[Browser]
    end
Loading

Dependencies Diagram

graph LR
    Shell[Shell App] --> Product[Product Package]
    Shell --> Checkout[Checkout Package]
    Shell --> Inspire[Inspire Package]

    Product --> UICore[UI Core]
    Checkout --> UICore
    Inspire --> UICore

    Shell --> React[React]
    Product --> React
    Checkout --> React
    Inspire --> React
Loading

Usage Example

Shell application:

import ProductSection from '@packages/ecommerce-sections-product'
import CheckoutSection from '@packages/ecommerce-sections-checkout'
import InspireSection from '@packages/ecommerce-sections-inspire'

Advantages

  • ✅ Separate development of sections as individual packages
  • ✅ Single bundle without additional HTTP requests
  • ✅ Simple debugging (one bundle, one source map)
  • ✅ Bundle size optimization at build time
  • ✅ Code isolation through packages, but unified build

Disadvantages

  • ❌ Requires rebuilding entire application when a package changes
  • ❌ Does not support independent deployment
  • ❌ Less flexible scaling compared to Runtime approach
  • ❌ All packages must be compatible at build time

Project Structure

apps/
└── ecommerce-bi-shell/        # Shell application
    ├── src/
    │   └── bootstrap.js       # Imports from packages
    └── webpack.config.js      # Regular webpack configuration

packages/
├── ecommerce-sections-product/  # Package for Product section
│   └── src/
│       └── index.js
├── ecommerce-sections-checkout/  # Package for Checkout section
└── ecommerce-sections-inspire/   # Package for Inspire section

Comparison Table of Approaches

Characteristic Monolith Runtime Integration Build Integration
Independent deployment
Separate development
Single bundle
Lazy loading modules
HTTP requests at runtime No Yes (remoteEntry.js) No
Setup complexity Low High Medium
Debugging Simple Complex Simple
Team scalability Low High Medium
Module isolation None Full Partial
Dependency versioning Unified Problematic Unified

Running the Project

Requirements

  • Node.js >= 14.0.0
  • npm >= 7.0.0
  • Yarn (recommended)

Installing Dependencies

yarn install

Building Shared Packages

yarn build

Running Monolithic Application

yarn dev:ecommerce-monolith

Application available at: http://localhost:3010/

Running Runtime Integration

yarn dev:ecommerce-mf-runtime-integration

This will start:

  • Shell application on port 3100
  • Product micro-frontend on port 3101
  • Checkout micro-frontend on port 3102
  • Inspire micro-frontend on port 3103

Shell application available at: http://localhost:3100/

Running Build Integration

yarn dev:ecommerce-mf-build-integration

Application available at: http://localhost:3200/

Running All Applications

yarn dev

Shared Packages

UI Core

Shared component library used by all approaches:

  • @ui-core/web-components - reusable React components (Card, Button, Input, etc.)

Configuration

Shared configuration packages:

  • @packages/config - shared configurations (Tailwind, ESLint, Axios)
  • @packages/tsconfig - TypeScript configurations (if used)

Architectural Decision

The project demonstrates three different approaches to organizing a frontend application in the context of microservices architecture. The choice of approach depends on the specific project requirements:

  • Monolith: Suitable for small teams and simple applications
  • Runtime Integration: Ideal for large organizations with many independent teams
  • Build Integration: A compromise between development flexibility and deployment simplicity

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published