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>oryarn list <package-name>to identify conflicting versions. - Dependency tree analysis: Tools like
npm-detect-secretsoryarn-deduplicatecan highlight version conflicts. - Build logs: Look for warnings about version mismatches during bundling (e.g., Webpack’s
statsoutput).
Solution¶
- Pin versions: Use
resolutionsinpackage.json(Yarn 2+) oroverrides(npm 8+) to enforce consistent versions. - Monorepo strategy: Centralize shared dependencies in a shared workspace (e.g., using
workspace:*inpackage.json). - Peer dependencies: Declare peer dependencies in shared libraries to ensure consumers install compatible versions.
Example:
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’sstatsorbundlephobiato 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 defaultorexport * fromto ensure all APIs are available. - Federated module validation: Use
@module-federation/validatorto 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-analyzerto 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()orReact.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 detectedin Webpack or Vite. - Dependency graph tools: Use
madgeorcycle.jsto 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-dependencyto catch issues.
Example:
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.,
babelpresets). - Environment variables: Ensure consistent
NODE_ENVand 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
resolutionsor 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.