Webpack Module Federation是Webpack 5引入的一个特性,它支持微前端架构,允许不同的Web应用之间共享模块,而不需要运行时的容器或服务器端的构建步骤。
假设有两个独立的React应用:app1和app2,其中app2将通过Module Federation作为远程模块被app1消费。
首先,在app2中配置Webpack以使其成为可被其他应用消费的远程微应用。
webpack.config.js (app2)
javascript
复制代码
const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); module.exports = { output: { publicPath: 'http://localhost:3002/', // 公共路径 uniqueName: 'app2', // 应用唯一标识 }, plugins: [ new HtmlWebpackPlugin({ template: './public/index.html', }), new ModuleFederationPlugin({ name: 'app2', // 微应用名称 library: { type: 'var', name: 'app2' }, // 导出方式 filename: 'remoteEntry.js', // 输出文件名 exposes: { './Button': './src/Button', // 暴露的模块 }, }), ], };
接下来,在app1中配置Webpack以消费来自app2的模块。
webpack.config.js (app1)
javascript
复制代码
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); module.exports = { output: { publicPath: 'http://localhost:3001/', }, plugins: [ new ModuleFederationPlugin({ name: 'app1', remotes: { app2: 'app2@http://localhost:3002/remoteEntry.js', // 引入app2的远程模块 }, }), ], };
在app1中,你可以像导入本地模块一样直接导入来自app2的模块。
App.js (app1/src)
jsx
复制代码
import React from 'react'; import { Button } from 'app2/Button'; function App() { return (
Welcome to App1
分别启动app1和app2,app1会成功地从app2加载并显示Button组件。
ModuleFederationPlugin
:是Webpack的核心插件,用于配置模块联邦。它允许应用声明自己暴露哪些模块给其他应用,以及从哪些远程应用消费模块。exposes
:在app2的配置中,通过exposes字段指定了要暴露给其他应用的模块路径,这里暴露了./src/Button作为一个名为Button的模块。remotes
:在app1的配置中,通过remotes字段定义了远程应用的名称(app2)及其远程Entry文件的URL。这使得app1能够找到并加载app2的模块。javascript
复制代码
shared: { react: { singleton: true, version: '17.0.2' }, 'react-dom': { singleton: true, version: '17.0.2' }, },
通过动态导入远程组件,可以实现按需加载,只在用户需要时才加载微应用,提高页面加载速度。 示例代码:
jsx
复制代码
import React, { lazy, Suspense } from 'react'; const Button = lazy(() => import('app2/Button')); function App() { return (
Welcome to App1
为了实现微应用之间的路由切换,可以使用single-spa
或react-router-dom
的Route组件,配合Microfrontends库来处理路由导航。 示例代码(使用react-router-dom
):
jsx
复制代码
import React from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import App1 from './App1'; import App2 from './App2'; function MainRouter() { return (
微应用之间可能需要进行通信,例如传递数据或触发事件。可以使用事件总线、MessageChannel API或自定义钩子函数实现跨应用通信。 示例(使用事件总线):
jsx
复制代码
// 在app1中发布事件 import { eventBus } from './eventBus'; eventBus.emit('customEvent', data); // 在app2中订阅事件 import { eventBus } from './eventBus'; eventBus.on('customEvent', (data) => { console.log('Received data:', data); });
确保微应用的加载和渲染顺序,避免依赖于未加载的微应用。可以使用single-spa的bootstrap和mount生命周期钩子进行控制。
如果需要服务端渲染,可以使用single-spa-react-server-rendering或next.js等库,确保微应用在服务器端也能正确渲染。
考虑到微应用可能由不同团队和时间点开发,需要制定兼容性和更新策略。例如,使用特定的Webpack版本,或者确保微应用的API兼容性。
单独测试每个微应用,同时确保整体应用的集成测试。 使用CD/CD(持续部署/持续交付)策略,自动化部署过程,确保微应用的快速迭代和更新。
实施统一的日志和监控系统,以便跟踪微应用的性能、错误和用户体验。
优化微应用之间的切换体验,如使用骨架屏或过渡动画,减少用户感知的延迟。
考虑微应用的安全性和权限控制,确保每个微应用只能访问必要的数据和资源。
原文链接:https://juejin.cn/post/7379149008357900297