服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

为什么说 Module Federation 天生是模块级的微前端?

日期: 来源:神光的编程秘籍收集编辑:神说要有光zxg

Module Federation 不是 webpack 5 的特性么?它和微前端有毛线关系?

不着急解释,我们先写个 Module Federation 的 demo 再说。

用 create-react-app 创建一个 react + webpack 的项目:

yarn create react-app aaa

然后进入项目目录执行

git init
git add .
git commit -m 'first commit'

之后执行

yarn run eject

默认 create-react-app 创建的项目不会暴露 react 配置文件,需要执行 eject 才会出来,但那之前需要把本地工作区的文件保存到 git 仓库才行。

这样就创建了一个 react + webpack 并且 webpack 配置文件可以修改的项目:

webpack 配置文件在这里:

同样的方式,再创建一个 bbb 项目。

现在我们就来通过 Module Federation 让 aaa 里的一个 Button 在 bbb 里面使用。

我们在 aaa 里加一个这样的 Button:

import './button.css';

export default function Button() {
    return <button className="guang">guang</button>
}
.guang {
    padding: 5px;
    color: #fff;
    background: blue;
    border-radius: 5px;
    border: 1px solid #fff;
}

yarn start 跑起开发服务,就可以看到它渲染出来是这样的:

我们想通过 Module Federation 把这个 Button 暴露出去该怎么做呢?

这样:

修改 webpack 配置文件,在 plugins 里添加这个插件:

const { ModuleFederationPlugin } = require('webpack').container;

new ModuleFederationPlugin({
    name: 'aaa_app',
    filename: 'aaaEntry.js',
    exposes: {
      './Button': './src/Button.jsx',
    }
})

它的含义就是创建一个 name 为 aaa_app 的共享包。

这个共享包 exposes 暴露出了 Button 这个共享模块。

它对应的文件名是 aaaEntry.js。

然后重新 yarn start 跑下开发服务器,刷新页面,你就会看到页面请求了 aaaEntry.js 这个文件:

里面声明了一个 aaa_app 的变量。

这就是说 webpack 把这个组件的代码分离到了这个文件里。

这样别的 webpack 应用就可以直接用这个组件了。

不信我们来试试看:

bbb 项目里同样修改 webpack 配置,引入这个插件:

const { ModuleFederationPlugin } = require('webpack').container;

new ModuleFederationPlugin({
    remotes: {
      'aaa-app': 'aaa_app@http://localhost:3001/aaaEntry.js',
    }
})

引入的时候使用 remotes 注册,这段配置就是注册了一个运行时的 Module,名字叫 aaa-app,它的值来自  http://localhost:3001/aaaEntry.js 这个文件里的 aaa_app 变量。

这样代码里就可以引入来用了:

因为是异步组件,所以用 React.lazy 包裹,具体取这个组件的逻辑就是用 webpack 提供的 import() 来异步加载模块。

这里通过 aaa-app/Button ,也就是共享包名/模块名的方式来引入。

跑下看看:

报错了,为什么呢?

看下网络,aaaEntry.js 这个文件已经被加载了呀:

只要取它的 aaa_app 变量不就行了么?

哪里有问题?

仔细看下你会发现,这个入口是 localhost:3001 下的文件没错:

但是它里面引入的这个 Button 却是 localhost:3002 下的:

那自然找不到了!

这是因为这时候 publicPath 不对:

所以去改下 aaa 的 ouput.publicPath 的配置,固定为 http://localhost:3001/

然后重新 yarn start,刷新下页面:

这时 publicPath 就对了,Button 的代码也就正常加载了:

这个 http://localhost:3002 就是 bbb 应用,可以看到它加载了 aaa 应用的 Button,渲染了出来。

而 http://localhost:3001 的 aaa 应用自然也有这个 Button:

这就是所谓的模块联邦 Module Federation !

感受到它能干什么了么?

Module Federation 能够把一个应用的一些模块导出,供别的应用异步引入这些模块。

方式就是一个应用通过 ModeleFederationPlugin 声明 exposes 的模块名字和路径,另一个应用通过 remotes 声明用到的一些模块来自于哪个文件的哪个变量。

这样当用到这个模块的时候,就回去异步请求对应的 url,取出其中的变量值。

这里要特别注意导出模块的应用需要固定 publicPath,不然加载文件的路径会有问题。

我们完成了一个应用导出 Button 在另一个应用里用,这个是单向的。

那反过来可不可以呢?

自然也是可以的,我们来试一下:

在 bbb 里添加这样一个 button:

import './button.css';

export default function Button() {
    return <button className="dong">dongdongdong</button>
}
.dong {
    padding: 5px;
    color: #fff;
    background: green;
    border-radius: 5px;
    border: 1px solid #fff;
}

渲染出来是这样的:

然后用 ModuleFederationPlugin 声明下 exposes 来导出它:

const { ModuleFederationPlugin } = require('webpack').container;

new ModuleFederationPlugin({
    name: 'bbb_app',
    filename: 'bbbEntry.js',
    exposes: {
      './Button': './src/Button.jsx'
    },
    remotes: {
      'aaa-app': 'aaa_app@http://localhost:3001/aaaEntry.js',
    }
})

在之前的基础上,同样加上 name(变量名)、fileName(文件名)、exposes(导出的模块)的配置。

然后配置 output.publicPath 固定为 http://localhost:3002/

然后去 aaa 应用里也改一下 ModuleFederationPlugin 的配置,引入这个 bbb 的导出:

const { ModuleFederationPlugin } = require('webpack').container;

new ModuleFederationPlugin({
    name: 'aaa_app',
    filename: 'aaaEntry.js',
    exposes: {
      './Button': './src/Button.jsx',
    },
    remotes: {
      'bbb-app': 'bbb_app@http://localhost:3002/bbbEntry.js',
    }
})

在组件里引入下:

重新跑一下 aaa 和 bbb 的 dev server。

然后刷新页面:

这时候你就可以看到 aaa 里面渲染了 bbb 的组件,bbb 里渲染了 aaa 的组件。

两个应用实现了模块的双向使用!

除了导出业务模块外,库的模块也可以共用,比如 react、react-dom 这种库。

两个应用都这样声明:

重新 yarn start 跑开发服务,然后刷新页面。

但这时会报错:

因为现在 react 和 react-dom 被分了出来,变成异步加载的模块了。

而你在入口里同步使用了异步模块导出 api 是不行的。

要改造一下,把原来的 index.js 改名为 bootstrap.js。

然后在新的 index.js 里异步 import 这个 bootstrap.js 就好了:

因为整个应用都变成了异步的,之前单独引入的异步组件的写法也就可以简化了:

这时就能正常渲染了:

而且 react、react-dom 这俩包,还有用到的 button 组件,都是异步加载的:

这些都是可以在 aaa、bbb 之间共享的模块,也就是模块联邦的模块!

这就是 Module Federation。

那回过头来看看最开始那个问题,为什么说 Module Federation 天生是模块级的微前端呢?

因为微前端做的事情不就是一个应用里复用另一个应用的代码么?

只不过一般是整个应用的共享,比如 qiankun 是在主应用里注册微应用的地址:

并且在微应用里写一下加载、卸载等生命周期的函数:

这样就可以在路由切换的时候自动加载微应用并执行它的生命周期函数来激活它。

微前端也就是多了一个异步加载应用的逻辑。

而 Module Federation 呢?

是在一个应用里注册另一个应用的模块代码:

当用到这些模块的时候,webpack 会异步加载对应的 chunk,拿到对应变量的值,也就是共享的模块。

这个和应用级别的微前端不是一样的流程么?

都是异步加载并执行代码。

只不过一个是应用级别,一个是模块级别。

所以说,模块联邦是天生的模块级的微前端。

总结

Module Federation 是 webpack5 提供的用于应用之间共享模块的机制,只要用 ModuleFederationPlugin 声明 exposes 的模块,另一个应用里用 ModuleFederationPlugin 声明 remotes 导入的模块,就可以直接用别的应用的模块了。

这就是它为什么会叫模块联邦。

除了业务模块外,库模块也可以共享。只不过要注意这些模块都是异步加载的,所以要用 import()来异步引入。

单独引入异步组件需要用 React.lazy(() => import('xx/yy')) 的形式,或者把整个应用用 import() 来异步加载。

此外,还要注意要固定 output.publicPath,不然引入模块的时候路径会有问题。

Module Federation 是天生的模块级微前端,它和 qiankun 一样,都是用到另一个应用的代码时,异步去某个地址下载它的代码,然后跑起来,只不过一个是应用级,一个是模块级。

相关阅读

  • 13 个你可能未使用过的 Python 技巧!

  • 来源丨关于数据分析与可视化大多数程序员不知道的令人难以置信的功能列表。Python 是顶级编程语言之一,它具有许多程序员从未使用过的许多隐藏功能。在这篇博客中,我将分享你
  • 这个常见动作致人死亡!被判9个月!千万注意

  • 开车门是司机上下车必然会做的一个动作,但如果不够小心,很可能就会上演“开门杀”,酿成事故。近日,江苏如东法院开庭审理了一起因开车门致人伤亡的交通肇事案件,被告人吴某犯交通
  • 气象兵,到!

  • 文、图 | 晏军敏、李伟辉、华禧一观察风云雷电预测阴晴雨雪有那么一群人他们站在星夜里胸怀经纬测风云他们时刻掌握飞行训练进度与安全把牢飞行训练保障的第一道关口他们就
  • 每日速递|多氟多目标2024年钠电正极产能7000吨

  • ◆电池◆01欣旺达正在开发钠离子电池3月23日,欣旺达在互动平台表示,相比于锂电池,钠电池的能量密度较低,适合应用于低速电动车和储能等领域,公司认为,钠电池是对锂电池的一种补充,
  • 菌说|大学“牲”解压迷惑行为大赏

  • 大学“牲”的生活如同升级打怪,总要面对层出不穷的压力。堆积的压力不仅会让自己心情低落,长此以往也不利于心理健康。那么,面对生活中的小颓丧,如何释放心中的压力和负能量呢?菌
  • @全球武大校友,母校呼叫你!

  • 启程珞珈山下传遍五洲寰宇看,在九一二体育场上正飘扬着一面校旗它即将飘洋过海给五湖四海的武大人送去“百卅”校庆的邀约@全球武大校友母校向你发出召唤啦伴着校歌的旋律国
  • 让自己越来越有价值的几种能力

  • 真正决定一个人价值的,不是学历,而是你的不可代替性。所以如何让我们越来越值钱,就在于你有没有能力让自己成为那个不可代替的人,脱颖而出。以下是能让你越来越有价值的能力,欢迎
  • 免费!三亚今年将为适龄女生接种HPV疫苗

  • 日前,《2023年三亚市适龄女生HPV疫苗接种项目实施方案》(以下简称《方案》)印发,将对全市5个区,2023年学籍在该市七年级及以上在校女生(第1剂次接种年龄满13周岁至14周岁半)免费接

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • 新增9个千亿县,江苏何以独揽4席

  • 全国GDP千亿县继续扩围。澎湃新闻梳理发现,2022年,全国千亿县数量达52个,较2021年增加9个,昆山、江阴、张家港继续领跑,其中,昆山成为全国首个GDP破5000亿元的县级市,达5006.7亿元
  • 星巴克“颠覆”星巴克:冲破第三空间

  • 来源丨全天候科技作者丨胡描图源丨摄图网经过长达一年的酝酿和测试,星巴克中国与高德地图合作的“沿街取”服务,在北京、上海两座城市的150家门店中正式上线。星巴克计划在未