Mastering Module Federation with Vite & Vue: A Step‑by‑Step Guide
Learn how to implement Webpack’s Module Federation using Vite and Vue, covering core concepts, advantages over traditional micro‑frontend solutions, detailed setup steps, code examples, and common pitfalls such as dependency conflicts and version mismatches.
What is Module Federation
In frontend projects, different teams may have coupled business modules; for example, Team A provides a rich‑text component that Team B also needs.
Traditionally, Team B would copy A’s code into its own project.
Webpack’s Module Federation allows a service to expose modules that other services can load at runtime, enabling dynamic sharing of components.
Vite can also achieve this via the vite-plugin-federation plugin.
Core Advantages of Module Federation
Key benefits include:
Independent deployment : each application can be developed, built, and deployed separately.
Runtime sharing : modules are loaded dynamically at runtime, not bundled at build time.
Version control : specific versions of shared modules can be declared, simplifying dependency management.
Reduced duplicate code : multiple apps can reuse the same functionality.
Compared with micro‑frontend solutions like qiankun, Module Federation offers finer‑grained, on‑demand loading of individual modules.
Implementation Example (Vite + Vue)
Assume we have two Vite projects:
ui-library: component provider exposing a button component (
SharedButton.vue).
main-app: host application that loads the button from
ui-libraryat runtime.
<code>shixiaoshi-demo/
├── ui-library/ # Remote module: exposes component
│ ├── src/SharedButton.vue
│ ├── vite.config.js
└── main-app/ # Host project: loads remote component
├── src/App.vue
├── vite.config.js
</code>1. Install the federation plugin
<code>npm install vite-plugin-federation --save-dev
</code>2. Expose the component
<code><template>
<button class="shared-btn">I am a shared button</button>
</template>
<script setup>
</script>
<style scoped>
.shared-btn {
padding: 10px;
background-color: teal;
color: white;
border: none;
border-radius: 5px;
}
</style>
</code> <code>import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import federation from '@originjs/vite-plugin-federation';
export default defineConfig({
plugins: [
vue(),
federation({
name: 'ui_library',
filename: 'remoteEntry.js',
exposes: {
'./SharedButton': './src/SharedButton.vue',
},
shared: ['vue'],
}),
],
build: {
target: 'esnext',
minify: false,
cssCodeSplit: false,
},
});
</code>Start the service
<code>npm run dev -- --port=5001
</code>Remote entry URL:
http://localhost:5001/assets/remoteEntry.js3. Load the remote component
<code>import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import federation from '@originjs/vite-plugin-federation';
export default defineConfig({
plugins: [
vue(),
federation({
name: 'main_app',
remotes: {
ui_library: 'http://localhost:5001/assets/remoteEntry.js',
},
shared: ['vue'],
}),
],
});
</code> <code><template>
<div>
<h1>Host Application</h1>
<RemoteButton />
</div>
</template>
<script setup>
import { defineAsyncComponent } from 'vue';
const RemoteButton = defineAsyncComponent(() => import('ui_library/SharedButton'));
</script>
</code> <code>npm run dev
</code>Visit
http://localhost:5173and you will see the button component from
ui-libraryrendered.
Relationship Diagram
<code>main-app (host)
|
| -- runtime request --> http://localhost:5001/assets/remoteEntry.js
|
| -- load --> SharedButton.vue exposed by ui-library
|
| -- use --> rendered as a local component in the host app
</code>Drawbacks
In practice, Module Federation can encounter issues such as:
Dependency conflicts : if the remote service depends on a specific Vue version that differs from the host’s version, the component may run with the host’s Vue instance, causing unexpected behavior.
State invalidation : remote components that rely on Vuex or Pinia may lose access to the correct store when executed in the host’s context.
Build configuration differences : plugins like unplugin-auto-import used in the remote service may not be present in the host, leading to missing API errors unless the functions are explicitly imported.
Therefore, it is recommended to keep framework versions, build tools, and plugin configurations consistent between host and remote modules, or provide adapter wrappers to isolate contexts.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.