一、什么是模块联邦
模块联邦(Module Federation)旨在解决前端微服务架构中的模块共享和应用集成问题。它使得不同的应用可以以独立的方式开发、构建和部署,同时可以共享和集成代码和资源。它提供了一种更灵活、松耦合的前端架构方式,有助于构建大型复杂应用和微服务体系结构。同时,模块联邦还提供了一些安全性措施,以确保远程应用和共享模块的安全性和可靠性。
简单理解:项目A可以直接引用项目B的组件
MF 引出下面两个概念:
- Host:引用了其他应用模块的应用, 即当前应用
- Remote:被其他应用使用模块的应用, 即远程应用
微前端与webpack 5 Module Federation - 掘金 (juejin.cn)
二、在vite中配置---在host端加载remote端导出的页面
2.1 安装 @originjs/vite-plugin-federation
vite-plugin-federation
是一款为vite
提供,用于支持多个独立构建的应用可以将自己的部分能力作为组件提供出来,组成一个应用程序。他们之间不存在相互依赖,可以进行独立的开发和部署。灵感来源于webpack 5
提供的Module Federation
特性。它通过vite
和rollup
提供的hock
,对构建文件进行干预,从而将所有远程模块的组件,汇总到remoteEntry.js
中。本地模块通过remoteEntry.js
入口,从而调用加载三方组件以及组件编译后的js
、css
等文件。
// 使用npm
npm install @originjs/vite-plugin-federation --save-dev
// 使用yarn
yarn add @originjs/vite-plugin-federation --dev
// 使用pnpm
pnpm install @originjs/vite-plugin-federation --D
2.2 新建项目文件
1.新建一个文件夹projects(自定义)
在该文件夹下创建两个项目,npm create vite@latest此命令重复两次即可
host-vite:动态加载、运行远程模块
remote-vite:提供远程模块
2.用vscode打开projects文件夹
注意:以下步骤重复两次(因为创建了两个项目,一个host端一个remote端)
右键点击host-vite,用集成终端(integrated)打开
安装依赖npm i
安装 @originjs/vite-plugin-federation
2.3 修改remote-vite的配置文件
1.修改vite.config.js
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';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
topLevelAwait(),
federation({
name: "remote-app",
filename:'remoteEntry.js', // 打包后生成该文件,需要导入到host
exposes: {
'./page1':'./src/components/page1.vue',
},
// 本地模块和远程模块共享的依赖
shared: ['vue'],
}),
],
})
2.运行npm run build进行打包
报错:assets/index-!~{001}~.js:52:45: ERROR: Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)
解决方案:
如果用pnpm安装报错可尝试用yarn
yarn add -D vite-plugin-top-level-await
Top-level await is not available in the configured target environment-CSDN博客
打包完成后的目录如下:
2.4修改host-vite端的配置文件
1.修改vite.config.js
关于remote_app1:'http://localhost:5173/dist/assets/remoteEntry.js'的解释
remote_app1:可以自定义,但在main.ts导入remote模块时要以该名称开头,再加上remote项目配置文件中暴露出的路径
http://localhost:5174为项目启动的地址
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: {
remote_app1:'http://localhost:5174/dist/assets/remoteEntry.js'
// remote_app2:'http://localhost:5175/dist/assets/remoteEntry.js'
},
shared: ['vue'],
}),
],
})
2. 修改main.ts
import { createApp,defineAsyncComponent } from 'vue'
// import './style.css'
import App from './App.vue'
// import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/reset.css'
const app = createApp(App)
const RemotePage1=defineAsyncComponent(()=>import('remote_app1/page1'))
// const RemotePage2=defineAsyncComponent(()=>import('remote_app2/page2'))
app.component('RemotePage1',RemotePage1)
// app.component('RemotePage2',RemotePage2)
app.mount('#app')
import报错
解决办法:在./src/vite-env..ts中添加
declare module 'remote_app1/page1'
declare module 'remote_app1/page2'
3.在模板中使用远程组件
修改components/test.vue并在App.vue中引入test.vue
<template>
<div>
<p>host</p>
<RemotePage1></RemotePage1>
</div>
</template>
并在App.vue中引入test.vue
<script setup lang="ts">
// import HelloWorld from './components/HelloWorld.vue'
import test from './components/test.vue'
// import page1 from 'remote_app1'
</script>
<template>
<!-- <HelloWorld msg="Vite + Vue" /> -->
<test></test>
<!-- <button>nihh</button> -->
</template>
<style scoped>
</style>
2.5 效果
三、模块联邦存在的问题---样式污染
- CSS 样式污染问题,建议避免在 component 中使用全局样式。
- 模块联邦并未提供沙箱能力,可能会导致 JS 变量污染
- 在 vite 中, React 项目还无法将 webpack 打包的模块公用模块
在开发过程中样式必须使用scoped
参考链接
更完整版可参考:基于vite配置模块联邦(修改版本)-CSDN博客