Setting Up Vite with Federation Plugins #
A comprehensive architectural walkthrough for implementing Module Federation in Vite ecosystems. This guide details plugin initialization, host/remote manifest configuration, runtime dependency resolution, and production build strategies for enterprise micro-frontends. Understanding the shift from Webpack’s runtime to Vite’s native ESM-based federation model is critical for teams adopting Webpack & Vite Module Federation Implementation architectural standards.
Key Implementation Objectives:
- Establish baseline plugin configuration for exposing and consuming remote modules.
- Align dependency sharing strategies with enterprise-grade runtime resolution patterns.
- Configure production builds to optimize chunk distribution and prevent cache invalidation storms.
Plugin Installation & Base Configuration #
Initialize the Vite project with federation capabilities and define core host/remote manifests using TypeScript-safe configuration. Begin by installing the official plugin and registering it in vite.config.ts. Define expose mappings for local components and remotes for external entry points. Configure shared blocks with explicit version pinning to prevent runtime collisions. For teams transitioning legacy setups, reference Migrating from Webpack to Vite for faster federation builds to align CI/CD pipeline adjustments with Vite’s native ESM resolution.
// vite.config.ts
import { defineConfig } from 'vite';
import federation from '@originjs/vite-plugin-federation';
export default defineConfig({
plugins: [
federation({
name: 'host_app',
remotes: {
remote_ui: 'http://localhost:5001/assets/remoteEntry.js'
},
shared: {
react: { singleton: true, requiredVersion: '^18.2.0' },
'react-dom': { singleton: true, requiredVersion: '^18.2.0' }
}
})
]
});
Runtime vs Build-Time Implications:
- Build-Time: The plugin parses the
remotesandsharedconfiguration to generate aremoteEntry.jsmanifest. Rollup statically analyzes imports to exclude shared dependencies from the host bundle. - Runtime: The host fetches the remote manifest at execution time. Singleton enforcement ensures only one instance of React/ReactDOM is loaded into memory, preventing duplicate framework instantiation and state desync.
Remote Module Consumption & Dynamic Imports #
Wire host applications to consume exposed remote components and handle async loading patterns without blocking the main thread. Implement import('remote_app/Component') syntax alongside framework-specific lazy loading utilities like React.lazy() or Vue’s defineAsyncComponent. Configure fallback UI states and error boundaries for failed remote resolutions. Unlike traditional setups, Vite’s static analysis approach contrasts sharply with Configuring Webpack Module Federation, enabling faster dev server cold starts and eliminating the need for complex runtime container bootstrapping scripts.
// FederatedView.tsx
import { lazy, Suspense } from 'react';
import ErrorBoundary from './ErrorBoundary';
const RemoteDashboard = lazy(() => import('remote_ui/Dashboard'));
export function FederatedView() {
return (
<ErrorBoundary fallback={<div>Module failed to load</div>}>
<Suspense fallback={<div>Loading remote module...</div>}>
<RemoteDashboard />
</Suspense>
</ErrorBoundary>
);
}
Runtime vs Build-Time Implications:
- Build-Time: Rollup treats the dynamic import as a code-splitting boundary. The remote module is not bundled into the host chunk; instead, a placeholder loader is generated.
- Runtime: The browser fetches the remote chunk asynchronously. Network latency, CORS misconfigurations, or remote server downtime trigger the
ErrorBoundaryfallback. Implementserver.proxyduring local development to bypass cross-origin manifest fetching restrictions.
Runtime Dependency Sharing & Version Conflicts #
Resolve singleton dependency collisions, manage cross-app state synchronization, and prevent duplicate framework bundling. Enforce singleton: true and strictVersion: true in the shared configuration for UI frameworks or state management libraries. Implement fallback version negotiation when remote apps request incompatible dependency ranges. Apply enterprise-scale resolution patterns from Managing Shared Dependencies at Runtime to isolate state boundaries and prevent memory leaks. For advanced manifest rewriting and hook overrides, extend plugin behavior using Using Vite plugin architecture for custom federation.
// shared.config.ts
export const sharedConfig = {
shared: {
'@tanstack/react-query': {
singleton: true,
requiredVersion: '^4.0.0',
strictVersion: true,
eager: true
},
'lodash-es': {
singleton: false,
requiredVersion: '^4.17.21',
strictVersion: false
}
}
};
Runtime vs Build-Time Implications:
- Build-Time:
eager: trueforces critical singletons into the initial bundle, deferring network requests for shared dependencies. Relaxed constraints (strictVersion: false) allow utility libraries to be duplicated if version negotiation fails, trading bundle size for runtime stability. - Runtime: The federation runtime evaluates the host’s installed dependency against the remote’s
requiredVersion. IfstrictVersion: trueand ranges mismatch, the plugin throws a runtime error before executing the remote module, preventing silent state corruption.
Cross-Origin Validation & Local Development Workflows #
Verify module resolution, enforce CORS compliance, and maintain Hot Module Replacement (HMR) across federated boundaries. Configure server.cors and server.origin to allow remote manifest injection during vite dev. Validate remote entry point availability using network inspector and vite preview staging. Debug HMR desync by isolating shared dependency updates and forcing full reloads on manifest changes. Implement automated smoke tests to verify remote chunk integrity before merging PRs, ensuring that federated contracts remain stable across independent deployment cycles.
Development Checklist:
- Set
server.cors: trueandserver.origin: 'http://localhost:5173'in the host config. - Run remote apps on distinct ports (
5001,5002, etc.) and verifyremoteEntry.jsis accessible via browser. - Use
vite previewto simulate production asset routing and validate chunk hashes. - Monitor WebSocket connections for HMR payloads; if remote updates fail to propagate, implement a lightweight polling script to trigger
window.location.reload().
Production Build Optimization & Asset Routing #
Finalize build outputs, optimize chunk splitting, and configure CDN/static hosting for federated assets. Adjust build.rollupOptions.output to enforce stable chunk hashing and prevent cache invalidation storms. Implement Optimizing chunk splitting for remote apps to reduce initial payload size and defer non-critical remote code. Configure static asset base paths and CDN rewrite rules to ensure remote manifests resolve correctly in production. Validate final bundle sizes using rollup-plugin-visualizer and enforce budget thresholds in CI pipelines.
Production Configuration Strategy:
- Asset Hashing: Use
entryFileNames: '[name]-[hash].js'andchunkFileNames: '[name]-[hash].js'to guarantee deterministic caching. - CDN Routing: Ensure remote
remoteEntry.jsand associated chunks are served withCache-Control: public, max-age=31536000, immutable. The manifest itself should use shorter TTLs or cache-busting query parameters. - Bundle Validation: Integrate
@rollup/plugin-visualizerin CI to track remote chunk weight. Reject PRs that exceed predefined size budgets for shared dependencies.
Common Pitfalls #
| Issue | Root Cause & Resolution |
|---|---|
| HMR desynchronization across federated boundaries | Vite’s native HMR does not automatically propagate to remote modules. Developers must implement manual manifest polling or configure server.hmr.overlay to trigger full reloads when remote entry points update. |
| Singleton dependency version mismatch at runtime | When host and remote apps specify incompatible requiredVersion ranges, the plugin throws a runtime error. Strict version checking must be paired with explicit peer dependency alignment in package.json. |
| CORS blocking remote manifest injection in production | Static hosting environments often block cross-origin script execution. Missing Access-Control-Allow-Origin headers on remote asset servers will prevent the host from fetching remoteEntry.js. |
FAQ #
Can Vite Module Federation work with non-ESM legacy dependencies?
Yes, but legacy CommonJS modules require explicit transformation via @rollup/plugin-commonjs or must be wrapped in ESM-compatible entry points before federation exposure. The plugin expects ES module syntax for static analysis and dynamic import resolution.
How do I handle remote module versioning without breaking the host?
Implement semantic version ranges in the shared config, enforce strictVersion: true for critical frameworks, and use dynamic import fallbacks to load alternative remote versions when negotiation fails. Version negotiation occurs at runtime; mismatched ranges trigger graceful degradation rather than hard crashes if fallbacks are configured.
Does Vite’s dev server support live reloading for remote apps?
Vite supports per-app HMR, but federated remotes require manual coordination. Configure server.proxy to route remote requests and implement a lightweight WebSocket listener to trigger host reloads on remote manifest updates. This ensures the host reflects remote component changes without full page refreshes during local development.