Skip to content

Common Pitfalls

Version Conflicts in Shared Dependencies

Problem

When multiple micro frontends or shared libraries depend on different versions of the same package (e.g., react or lodash), version mismatches can cause runtime errors, broken functionality, or unexpected behavior.

Diagnosis

  • Check installed versions: Use npm ls <package-name> or yarn list <package-name> to identify conflicting versions.
  • Dependency tree analysis: Tools like npm-detect-secrets or yarn-deduplicate can highlight version conflicts.
  • Build logs: Look for warnings about version mismatches during bundling (e.g., Webpack’s stats output).

Solution

  • Pin versions: Use resolutions in package.json (Yarn 2+) or overrides (npm 8+) to enforce consistent versions.
  • Monorepo strategy: Centralize shared dependencies in a shared workspace (e.g., using workspace:* in package.json).
  • Peer dependencies: Declare peer dependencies in shared libraries to ensure consumers install compatible versions.

Example:

# Yarn 2+ resolutions in package.json
"resolutions": {
  "react": "18.2.0",
  "react-dom": "18.2.0"
}


Missing Exports in Federated Modules

Problem

Shared modules may fail to expose required APIs, leading to ReferenceError or undefined in consuming apps. This often occurs with dynamic imports or missing default/Named exports.

Diagnosis

  • Verify exports: Use webpack’s stats or bundlephobia to inspect exported symbols.
  • Runtime checks: Add logging or try/catch blocks to detect missing exports at runtime.
  • Documentation gaps: Ensure shared modules document all exported APIs.

Solution

  • Explicit exports: Use export default or export * from to ensure all APIs are available.
  • Federated module validation: Use @module-federation/validator to check exports during build.
  • Fallback defaults: Provide default values for optional exports to avoid crashes.

Example:

// Shared module (shared-utils.js)
export const formatCurrency = (value) => `${value.toFixed(2)} USD`;


Network Latency in Remote Modules

Problem

Remote modules loaded via federation (e.g., via @module-federation/remote-entry) can introduce latency, especially over slow networks or with large bundles.

Diagnosis

  • Network monitoring: Use browser devtools to measure load times for remote modules.
  • Bundle size analysis: Check webpack-bundle-analyzer to identify oversized modules.
  • Caching: Verify if remote modules are cached in the browser or CDN.

Solution

  • Lazy loading: Load remote modules on demand using import() or React.lazy.
  • CDN optimization: Host remote modules on a global CDN to reduce latency.
  • Preloading: Use <link rel="preload"> for critical remote modules.

Example:

// React.lazy with Suspense
const RemoteComponent = React.lazy(() => import('http://remote-entry.com/remote-module'));


Circular Dependencies in Federated Systems

Problem

Circular dependencies between micro frontends or shared modules can cause infinite loops, build failures, or runtime errors.

Diagnosis

  • Build logs: Look for errors like Circular dependency detected in Webpack or Vite.
  • Dependency graph tools: Use madge or cycle.js to visualize dependency chains.
  • Code reviews: Identify mutual imports between modules.

Solution

  • Refactor dependencies: Break cycles by splitting modules or using interfaces.
  • Dependency injection: Replace direct imports with service providers or context APIs.
  • Build-time validation: Use tools like eslint-plugin-circular-dependency to catch issues.

Example:

# Detect circular dependencies
npx madge --circular src/


Inconsistent Build Configurations

Problem

Divergent build tools (e.g., Webpack, Vite, Rollup) or configurations can lead to incompatible output formats, missing plugins, or broken federation.

Diagnosis

  • Build output inspection: Compare generated bundles for discrepancies.
  • Plugin conflicts: Check for overlapping or incompatible plugins (e.g., babel presets).
  • Environment variables: Ensure consistent NODE_ENV and build flags across projects.

Solution

  • Standardize tooling: Use a unified build system (e.g., Webpack 5) across all micro frontends.
  • Shared config files: Extract common configurations into a shared monorepo folder.
  • CI validation: Automate build checks to catch configuration drift.

Example:

// Shared Webpack config (webpack.shared.js)
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};


Key takeaways

  • Version conflicts can be resolved with resolutions or monorepo strategies.
  • Missing exports require explicit declarations and validation tools.
  • Network latency is mitigated via lazy loading, CDNs, and preloading.
  • Circular dependencies demand refactoring or dependency injection.
  • Consistent build configs ensure compatibility across tools and environments.