前言
Module Federation 中文直译为"模块联邦",而在 webpack 官方文档中,其实并未给出其真正含义,但给出了使用该功能的 motivation
, 即动机,翻译成中文
多个独立的构建可以形成一个应用程序。这些独立的构建不会相互依赖,因此可以单独开发和部署它们。这通常被称为微前端,但并不仅限于此。
该功能很好的解决了多应用模块复用的问题,相比之前的发布成npm包或者使用iframe的方式,更加优雅和灵活。
webpack中可以实现该功能,那么在vite项目中可以实现吗?答案是当然可以啦!!!
如何配置模块联邦
MF 引出下面两个概念:
- Host:引用了其他应用模块的应用, 即当前应用
- Remote:被其他应用使用模块的应用, 即远程应用
实战
第一步
先用vite创建两个项目,项目名就叫app1和app2。
在app1中安装如下依赖
sql
yarn add @originjs/vite-plugin-federation --dev
yarn add vite-plugin-top-level-await --dev
在app2中安装如下依赖
sql
yarn add @originjs/vite-plugin-federation --dev
第二步
在app1项目中vite.config.js配置如下
js
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import federation from "@originjs/vite-plugin-federation";
import topLevelAwait from 'vite-plugin-top-level-await'
export default defineConfig({
plugins: [
vue(),
federation({
name: 'app1',
filename: 'remoteEntry.js',
// Modules to expose
exposes: {
'./Button': './src/Button.vue',
},
shared: {
vue:{
generate:false
}
}
}),
// 重要
topLevelAwait({
// The export name of top-level await promise for each chunk module
promiseExportName: "__tla",
// The function to generate import names of top-level await promise in each chunk module
promiseImportName: i => `__tla_${i}`
})
]
})
在app1项目中src目录下创建一个组件,叫Button.vue
vue
<template>
<button>确定</button>
</template>
<script setup>
import {onMounted} from 'vue'
onMounted(()=>{
console.log('vue3 mf')
})
</script>
<style>
第三步
在app2项目中vite.config.ts配置如下
ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import federation from "@originjs/vite-plugin-federation";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
federation({
name: 'host-app',
remotes: {
// 注意该路径,写错了可能会在项目中无法引用到远端组件
app1: "http://localhost:5173/dist/assets/remoteEntry.js",
},
shared: ['vue']
})
],
})
在app2项目的main.ts中引入远端组件
ts
import App from './App.vue'
import { createApp, defineAsyncComponent } from "vue";
const app = createApp(App);
const RemoteButton = defineAsyncComponent(() => import("app1/Button"));
app.component("RemoteButton", RemoteButton);
app.mount("#app");
然后在app2项目的App组件中使用RemoteButton组件即可
注意:在使用前需要先把app1项目build一次,不能同时在开发环境下使用。由于 Vite 是按需编译,所以 app1 必须先打包启动,2 个 App 无法同时是开发模式。
之后启动app2项目就可以看到正常能加载app1项目中的组件了,可以完美复用。