Skip to content

edwardloopez/travel-app-repack-example

Repository files navigation

🌍 Travel App - Module Federation V2 Super App Architecture

A comprehensive React Native super app demonstrating Module Federation V2 with Re.Pack 5.x, showcasing micro-frontend architecture patterns and advanced bundle management.

πŸ“‹ Table of Contents


πŸ—οΈ Architecture Overview

This project demonstrates a Module Federation V2 super app architecture with the following micro-frontends:

graph TB
    Host[Travel Host App<br/>Port: 8081] --> Weather[Weather MF<br/>Port: 9000]
    Host --> Destinations[Destinations MF<br/>Port: 9001]
    Host --> Search[Search MF<br/>Port: 9002]
    Host --> Photos[Photos MF<br/>Port: 9003]

    Host --> Core[travel-core<br/>Shared Package]
    Weather --> Core
    Destinations --> Core
    Search --> Core
    Photos --> Core

    Host --> SDK[travel-sdk<br/>Dependency Manager]
Loading

Key Benefits Achieved

  • βœ… Manifest-Based Resolution: Automatic remote discovery via JSON manifests
  • βœ… Platform Agnostic: Dynamic ${platform} interpolation for iOS/Android
  • βœ… Zero Configuration: No custom resolvers or URL management needed
  • βœ… Version Management: Built-in caching and dependency sharing
  • βœ… Developer Experience: Hot reloading across micro-frontends
  • βœ… Type Safety: Enhanced TypeScript integration

πŸŽ“ Key Learnings

1. The Manifest Magic

MF V2's manifest system (mf-manifest.json) provides:

  • Automatic remote discovery
  • Platform-specific resolution (${platform} interpolation)
  • Built-in version management
  • Zero configuration complexity
// Simple, declarative configuration
remotes: {
  TravelWeather: `TravelWeather@http://localhost:9000/${platform}/mf-manifest.json`,
  TravelDestinations: `TravelDestinations@http://localhost:9001/${platform}/mf-manifest.json`
}

2. Re.Pack 5.x + Rspack = Performance

The combination delivers:

  • Fast builds with Rspack's Rust-based bundling
  • Hot reloading across micro-frontends
  • Tree shaking for optimal bundle sizes
  • Hermes bytecode support for production

3. ModuleFederationPluginV2 Features

The enhanced plugin provides:

  • Manifest-based resolution: No manual URL management
  • Dynamic type hinting: Better TypeScript integration
  • Runtime plugin system: Extensible architecture
  • Built-in optimization: Automatic dependency sharing

πŸ› οΈ Dependencies & Tooling

Essential Dependencies

Package Version Purpose
@callstack/repack 5.2.5 React Native bundling with Module Federation
@module-federation/enhanced 2.5.1 Enhanced MF features
@module-federation/runtime 2.5.1 MF runtime (registerRemotes, plugins)
@rspack/core ^1.4.0 Fast Rust-based bundler
@swc/helpers 0.5.15 SWC transformation helpers

Workspace Management

Tool Purpose Configuration
pnpm Package manager with workspace support pnpm-workspace.yaml
concurrently Multi-process dev server (pnpm start) root package.json

React Native Stack

  • React Native: 0.80.2
  • React: 19.1.0
  • Expo: ~53.0.22
  • Node.js: >=22 (engineStrict; 22.18+ recommended for native TypeScript rspack configs; older 22.x uses jiti automatically)

πŸ“ Project Structure

travel-app-repack-example/
β”œβ”€β”€ πŸ“± apps/                          # Micro-frontend applications
β”‚   β”œβ”€β”€ travel-host/                  # Main host app (Port: 8081)
β”‚   β”‚   β”œβ”€β”€ rspack.config.ts         # MF V2 host (runtime remotes)
β”‚   β”‚   └── src/federation/           # Dynamic remote registration
β”‚   β”œβ”€β”€ travel-weather/               # Weather MF (Port: 9000)
β”‚   β”œβ”€β”€ travel-destinations/          # Destinations MF (Port: 9001)
β”‚   β”œβ”€β”€ travel-search/               # Search MF (Port: 9002)
β”‚   └── travel-photos/               # Photos MF (Port: 9003)
β”œβ”€β”€ πŸ“¦ packages/                      # Shared packages
β”‚   β”œβ”€β”€ travel-core/                  # Core utilities & components
β”‚   β”‚   β”œβ”€β”€ src/components/           # Shared UI components
β”‚   β”‚   β”œβ”€β”€ src/context/             # Global state management
β”‚   β”‚   └── src/utils/               # Utility functions
β”‚   └── travel-sdk/                   # Dependency management SDK (plain JS, no build step)
β”‚       β”œβ”€β”€ index.js                  # Public exports
β”‚       β”œβ”€β”€ lib/dependencies.json     # Centralized dependency versions
β”‚       β”œβ”€β”€ lib/sharedDeps.js         # MF shared dependencies factory
β”‚       β”œβ”€β”€ lib/createRspackConfig.js # Rspack factory for host/remotes
β”‚       β”œβ”€β”€ lib/remotes.config.js     # Static remote metadata (slug, ports, UI)
β”‚       β”œβ”€β”€ lib/remote-registry.dev.json   # Generated dev registry (committed)
β”‚       β”œβ”€β”€ lib/remote-registry.prod.json  # Bundled prod fallback (generated)
β”‚       β”œβ”€β”€ lib/remoteProfiles.js     # buildRegistryJson, buildHostRemotes
β”‚       └── lib/writeRemoteArtifacts.js
β”œβ”€β”€ remotes-dist/                    # Pre-built remote bundles + registry
β”œβ”€β”€ scripts/                         # build-remotes, generate-registry, serve-remotes
β”œβ”€β”€ βš™οΈ Configuration Files
β”‚   β”œβ”€β”€ pnpm-workspace.yaml          # PNPM workspace definition
β”‚   └── tsconfig.json                # Root TypeScript config
└── πŸ“š docs/                         # Documentation

πŸš€ Setup & Installation

Prerequisites

# Required versions
node --version    # >= 22.0.0
pnpm --version    # >= 10.10.0

Installation Steps

# 1. Clone and install dependencies
git clone <repository-url>
cd travel-app-repack-example
pnpm install

# CI uses frozen lockfile: pnpm install:ci
# Supply-chain hardening: see docs/SECURITY-PNPM.md

# 2. iOS setup (if developing for iOS)
cd apps/travel-host/ios
pod install
cd ../../..

# 3. Start all micro-frontends
pnpm start  # concurrently: host + 4 remotes

# Alternative: Start individually
pnpm start:travel-host        # Host app
pnpm start:travel-weather     # Weather MF
pnpm start:travel-destinations # Destinations MF
pnpm start:travel-search      # Search MF
pnpm start:travel-photos      # Photos MF

Running on Device

# iOS
pnpm run:travel-host:ios

# Android
pnpm run:travel-host:android

πŸ”§ Development Workflow

1. Multi-Process Development (Recommended)

# Start all services (host + remotes)
pnpm start

This launches:

  • Host app on port 8081
  • Weather MF on port 9000
  • Destinations MF on port 9001
  • Search MF on port 9002
  • Photos MF on port 9003

2. Individual Development

# Terminal 1: Host
pnpm start:travel-host

# Terminal 2: Specific micro-frontend
pnpm start:travel-weather

3. Dev vs Prod (no REMOTE_PROFILE env var)

Profile is derived automatically:

Mode Runtime MF URLs Registry
dev __DEV__ Live bundlers :9000-9003 (build-time rspack) Bundled remote-registry.dev.json
prod release build CDN / :4100 fallback fetch(remote-registry.json) + registerRemotes()

Dev MF URLs use localhost (simulator). Prod registry URL: app.config.ts β†’ extra.remoteRegistryUrl.

# Dev (default debug build)
pnpm start

# Prod-like local test (release build + static bundles)
pnpm build:remotes:ios              # all remotes
pnpm build:remotes:ios -- weather    # one remote (also: search, TravelWeather, etc.)
pnpm serve:remotes                  # :4100
pnpm run:travel-host:ios:release

# Regenerate registry only (reads version from each micro-app package.json)
pnpm generate:registry

# Do NOT use `expo run:ios --configuration Release` β€” Expo pre-bundles with Metro
# and cannot resolve federated imports (e.g. TravelPhotos/PhotosScreen).
# Release uses react-native CLI + Re.Pack (see apps/travel-host/ios/.xcode.env.updates).

4. Remote version bumps (release cache)

Each micro-app version lives in its own package.json. Run pnpm generate:registry (or build:remotes) to refresh remote-registry.dev.json and remotes-dist/remote-registry.json.

# 1. Bump version in the micro-app
# apps/travel-weather/package.json β†’ "version": "1.0.2"

# 2. Build bundle(s) and regenerate registry
pnpm build:remotes:ios -- weather

# 3. Rebuild host release and reopen the app
pnpm run:travel-host:ios:release

On app start, checkForUpdates() compares the installed bundle version (bundle_installed_* in AsyncStorage) with the registry and invalidates ScriptManager cache when they differ.

4. Standalone Mode

Each micro-frontend can run independently:

pnpm start:standalone:travel-weather

βš™οΈ Configuration Deep Dive

1. Module Federation V2 Host Configuration

// apps/travel-host/rspack.config.ts β€” remotes registered at runtime
new Repack.plugins.ModuleFederationPluginV2({
  name: 'TravelHost',
  dts: false,
  remotes: {},
  shared: getSharedDependencies({ eager: true }),
  runtimePlugins: ['./mf-fetch-plugin.ts'],
});

// apps/travel-host/src/federation/initRemotes.ts
registerRemotes(registry.remotes); // from remote-registry.json or dev config

2. Module Federation V2 Remote Configuration

// apps/travel-weather/rspack.config.ts β€” via createRemoteRspackConfig from travel-sdk
export default createRemoteRspackConfig({
  mfName: 'TravelWeather',
  exposes: {
    './App': './src/navigation/MainNavigator',
  },
  shared: getSharedDependencies({ eager: false }),
});

3. RNEF Configuration

// rnef.config.mjs
export default {
  bundler: pluginRepack(),
  platforms: {
    ios: platformIOS(),
    android: platformAndroid(),
  },
  remoteCacheProvider: null,
};

4. Shared Dependencies Management

// packages/travel-sdk/lib/sharedDeps.js
export default function getSharedDependencies({ eager = true } = {}) {
  const dependencies = /* read from ./dependencies.json */;

  const shared = Object.entries(dependencies).map(([dep, { version }]) => {
    return [dep, { singleton: true, eager, requiredVersion: version, version }];
  });

  return Object.fromEntries(shared);
}

5. Monorepo scripts (pnpm)

Replaced by pnpm workspaces. Root scripts orchestrate tasks across packages:

{
  "typecheck": "pnpm -r --if-present run typecheck",
  "lint:check": "pnpm -r --if-present run lint",
  "test": "pnpm -r --if-present run test"
}

6. Multi-Process Development Setup

pnpm start uses concurrently to run host and remotes in one terminal:

pnpm start
# Or start individually:
pnpm start:travel-host
pnpm start:travel-weather

πŸ› Troubleshooting

Common Issues & Solutions

1. Manifest Loading Issues

Issue: Remote manifests fail to load

Debug Steps:

# Check if manifest is accessible
curl http://localhost:9000/android/mf-manifest.json

# Verify manifest structure
cat apps/travel-weather/dist/android/mf-manifest.json

Solution: Ensure remote is running and ports are correct

2. Port Conflicts

Issue: Multiple services trying to use the same port

Solution: Check port allocation in package.json scripts:

  • Host: 8081
  • Weather: 9000
  • Destinations: 9001
  • Search: 9002
  • Photos: 9003

3. Platform Resolution Issues

Issue: Incorrect platform detection in manifest URLs

Solution: Verify platform interpolation:

// Ensure ${platform} resolves correctly
remotes: {
  TravelWeather: `TravelWeather@http://localhost:9000/${platform}/mf-manifest.json`;
}

4. Shared Dependency Mismatches

Issue: Version conflicts between host and remotes

Solution: Use centralized dependency management:

// packages/travel-sdk/lib/dependencies.json
{
  "react": { "version": "19.0.0" },
  "react-native": { "version": "0.79.5" }
}

5. Bundle Loading Failures

Issue: Remote bundles fail to load

Debug Steps:

# Check manifest accessibility
curl http://localhost:9000/android/mf-manifest.json

# Monitor network requests
adb logcat | grep -i "module federation"

# Enable MF debugging
console.log('MF V2 Debug:', window.__FEDERATION__);

⚑ Performance Optimization

1. Bundle Optimization

// Enable Hermes bytecode for production
new Repack.plugins.HermesBytecodePlugin({
  enabled: mode === 'production',
  test: /\.(js)?bundle$/,
  exclude: /index.bundle$/,
});

2. Shared Dependencies Strategy

// Host: Eager loading for core dependencies
shared: getSharedDependencies({ eager: true });

// Remotes: Lazy loading for optimal startup
shared: getSharedDependencies({ eager: false });

3. Build Caching

Use Re.Pack / CI cache for bundle:ios and bundle:remote:* outputs under each app's build/ directory.


🎯 Best Practices

1. Dependency Management

  • Centralize shared dependencies in travel-sdk
  • Use exact versions for consistency
  • Regular dependency audits

2. Development Workflow

  • Use pnpm start for orchestrated development (or individual start:travel-* scripts)
  • Enable hot reloading for fast iterations
  • Implement proper error boundaries

3. Code Organization

  • Keep micro-frontends loosely coupled
  • Share common UI through travel-core
  • Use TypeScript for type safety

4. Performance

  • Lazy load non-critical micro-frontends
  • Optimize bundle sizes with tree shaking
  • Use Hermes for production builds

πŸ“š Additional Resources


🀝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests if applicable
  5. Submit a pull request

πŸ“„ License

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


Built with ❀️ using Module Federation V2, Re.Pack 5.x, and React Native 0.80.2

About

A comprehensive React Native super app demonstrating Module Federation V2 with Re.Pack 5.x, showcasing micro-frontend architecture patterns and advanced bundle management.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors