qiankun使用webpack5 module federation实践
qiankun
qiankun 是一个基于 single-spa 的微前端实现库,微应用能够独立开发独立部署。
什么是微前端
Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently. -- Micro Frontends
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。
微前端架构具备以下几个核心价值:
-
技术栈无关 主框架不限制接入应用的技术栈,微应用具备完全自主权
-
独立开发、独立部署 微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
-
增量升级
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
-
独立运行时 每个微应用之间状态隔离,运行时状态不共享
Module Federation(模块联邦)
模块联邦也是一种微前端,可以颗粒化到单页应用或者组件。 每个字应用单独构建,主应用在运行时通过容器加载远程模块即子应用的构建。主应用自动使用子应用当前版本的最新资源。
实例,项目均接入qiankun
项目mf1, 提供共享模块(qiankun子项目)
mf1 共享模块为src/components/Button
import React from 'react';
const Button =() => {
return (<div><button>我是mf1的button</button></div>);
}
export default Button;
mf1 的config 配置
const { ModuleFederationPlugin } = require("webpack").container;
const { REACT_APP_ENV, NODE_ENV } = process.env;
const publicPath = NODE_ENV === 'production' ? '/publicPath' : '/';
/**
* dev 环境
* publicPath: '/qiankun/zeusCI/', 则必须注释掉 memo.output.publicPath('auto')项目才能正确运行。 MF exposes不可用
* publicPath: '/', 则无须注释掉 memo.output.publicPath('auto')。 MF exposes可用
* 建议: dev 环境publicPath改为 '/'
*/
export default defineConfig({
base: '/xxx',
publicPath,
qiankun: {
slave: {
}
},
antd: {},
dva: {
hmr: true,
},
history: {
type: 'hash',
},
dynamicImport: {
loading: '@/components/PageLoading/index',
},
mfsu:{}, // umi3.5.13版本引入,加速构建
webpack5: {},
chainWebpack(memo) {
memo.output.publicPath('auto'); // 请看上面注释
memo
.plugin('mf')
.use(ModuleFederationPlugin, [{
name: "mf1", // 该名称必须与入口名称相匹配
filename: 'remoteEntry.js',
exposes: {
"./Button": './src/components/Button/index', // 共享模块
},
}]);
},
targets: {
ie: 11,
},
// umi routes: https://umijs.org/docs/routing
routes,
// Theme for antd: https://ant.design/docs/react/customize-theme-cn
theme: {
'primary-color': defaultSettings.primaryColor,
},
title: false,
ignoreMomentLocale: true,
proxy: proxy[REACT_APP_ENV || 'dev'],
manifest: {
basePath: '/xxx',
},
exportStatic: {},
esbuild: {},
});
项目2,引入mf1共享模块并使用(qiankun子项目)
项目2 page/index
import styles from './index.less';
import React from 'react'
import {Card} from 'antd'
const Mf1Button = React.lazy(() => import("mf1/Button"));
export default function IndexPage() {
return (
<div>
<Card title="module federatino 应用">
<React.Suspense fallback='loading'>
<Mf1Button />
</React.Suspense>
</Card>
</div>
</div>
);
}
项目2 config配置
qiankun: {
slave: {}
},
antd: {},
dva: {
hmr: true,
},
plugins: [
],
locale: {
// default zh-CN
default: 'zh-CN',
// default true, when it is true, will use `navigator.language` overwrite default
baseNavigator: true,
},
dynamicImport: {
loading: '@/components/PageLoading/index',
},
webpack5: {},
chainWebpack(memo) {
memo.output.publicPath('auto');
memo
.plugin('mf')
.use(ModuleFederationPlugin, [{
name: "submodule",
filename: 'submodule.js',
exposes:{
"./ProductList": './src/components/ProductList/index'
},
remotes: { // 引用远程模块
// dev环境 "mf1@//localhost:7001/remoteEntry.js"
mf1: "mf1@//xxxx.com/publicPath/remoteEntry.js"
},
}])
},
项目2启动
注意⚠️
共享模块不允许使用hooks
remotes 不需要加https或者http
exposes 必须为
"./Button": "...."
- 'Button': './src/components/Button'
+ './Button':'./src/components/Button'
总结
模块联邦提供单独构建单独部署,主应用只在运行时加载。主体应用程序将常用库定义为共享模块,以避免在页面构建中出现重复。相对npm包有很大的便捷性。 但是和qiankun混搭时,实操效果不佳。目前来看项目中采用MF,建议使用CRA初始化项目,或者emp架构。
以上个人拙见,欢迎指教。
转载自:https://juejin.cn/post/6987998229485289486