尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

前端精读周刊深度解析:Webpack5 模块联邦(Module Federation)如何让跨应用代码共享走向 Runtime

前端精读周刊深度解析:Webpack5 模块联邦(Module Federation)如何让跨应用代码共享走向 Runtime 文档技术博客教程【免费下载链接】weekly前端精读周刊。帮你理解最前沿、实用的技术。项目地址https://gitcode.com/GitHub_Trending/we/weekly点击查看免费下载导读本文基于前端精读周刊第 144 期对 Webpack5 模块联邦Module Federation / Federated Module的深度解读系统梳理 NPM、UMD、微前端、模块联邦四种跨应用模块共享方式的演进脉络完整拆解ModuleFederationPlugin的name、remotes、exposes、shared四大核心参数并给出 Host 与 Remote 双侧可运行的 Webpack 配置与调用示例。读完你将掌握模块联邦解决的是哪些问题、它相比传统方案的优势与适用场景、以及如何在项目中落地远程模块的暴露与消费。1 引言从构建后共享到运行时共享先说结论Webpack5 模块联邦让 Webpack 达到了线上 Runtime 的效果——代码可以直接在项目间利用 CDN 共享不再需要本地安装 Npm 包、重新构建再发布。在 Webpack5 之前我们通常通过 DLL动态链接库或 Externals 在单个应用内部做代码共享抽 Common Chunk但一旦上升到不同应用、不同项目之间任务就变得异常困难我们几乎无法在项目之间做到按需热插拔Hot Plug / Hot Unplug。模块联邦是 Webpack5 新内置的一个重要功能它让跨应用间真正做到模块共享。本文将结合 webpack-5-module-federation-a-game-changer-in-javascript-architecture 这篇业界文章的核心思想讲清楚模块联邦到底是什么、怎么用、以及它背后的运行时设计逻辑。2 模块共享方式的演进从 NPM 到模块联邦要理解模块联邦的价值先要理解它出现之前跨应用共享模块的几种主流方式及其各自的局限。2.1 NPM 方式共享模块想象一下最正常的共享模块方式——对就是 NPM。正常流程是将共享代码抽成一个独立的 Lib 包 → 发布到 NPM 仓库 → 在每个需要它的项目中通过npm install安装 → 再经过 Webpack 本地打包构建 → 最后上线。对于项目 Home 与 Search需要共享一个模块时最常见的办法就是将其抽成通用依赖并分别安装在各自项目中。这种方式的痛点非常明显重复构建每个消费项目都要把共享 Lib 重新打包一遍代码无法真正复用构建产物版本割裂共享包升级后所有消费方必须各自升级依赖并重新构建发布节奏很难对齐发布链路长改一个共享模块要走改包 → 发版 → 各项目升级 → 各项目重新构建 → 各项目发布的完整链路。虽然 Monorepo 的优势 一文提到Monorepo 可以一定程度解决重复安装和修改困难的问题——例如将多个子项目源码聚合在一个仓库中通过tsconfig.json的paths与 Webpack 的alias实现虚拟模块路径避免重复安装依赖——但即便在 Monorepo 中共享代码依然需要走本地编译并没有跳出先构建、再上线的框架。2.2 UMD 方式共享模块真正偏向 Runtime 的方式是 UMD 方式即将模块用 Webpack 的 UMDUniversal Module Definition模式打包产出 UMD 包后由其他项目在运行时直接引用。对于项目 Home 与 Search可以直接利用同一个 UMD 包复用一个模块无需在各自项目中重复打包该模块。这是非常普遍的模块共享方式其优势是产物即所得消费方直接加载已经打包好的代码。但这种技术方案问题也很明显包体积无法达到本地编译时的优化效果UMD 包是独立打包的无法与消费方应用的代码一起做 Tree Shaking、作用域提升Scope Hoisting等整体优化库之间容易冲突多个 UMD 包可能各自带一份相同的第三方依赖比如各自打包一份 React全局作用域下容易互相污染、互相冲突。2.3 微前端方式共享模块微前端Micro-Frontends简称 MFE是近年来比较火的模块共享管理方式。微前端要解决的核心问题是多项目并存而多项目并存的最大问题就是模块共享时不能有冲突。需要说明的是微前端还需要考虑样式冲突隔离、生命周期管理等复杂问题而本文聚焦在资源加载方式这一个维度上。微前端一般有两种打包方式子应用独立打包模块更解耦各子应用可以独立开发、独立部署但缺点是无法抽取公共依赖同一个公共库会被多个子应用重复加载整体应用一起打包可以很好地解决公共依赖抽取问题但打包速度实在是太慢而且不具备水平扩展能力——每次改动都要整体重新构建应用规模增大后构建成本不可接受。也就是说微前端的两条路线在解耦与共享之间是二选一的要么拆得干净但依赖重复要么合在一起但构建低效。2.4 模块联邦方式两全其美终于提到本文的主角了——作为 Webpack5 内置核心特性之一的Federated Module联邦模块。模块联邦方案的核心理念是直接将一个应用的构建产物应用于另一个应用同时具备整体应用一起打包时的公共依赖抽取能力。这意味着它同时解决了微前端两大路线的矛盾应用之间依然保持独立构建、独立部署具备子应用独立打包的解耦性又能通过共享依赖shared机制在运行时复用公共库具备整体打包的依赖抽取能力。从架构形态上看模块联邦让应用具备模块化输出能力其实开辟了一种新的应用形态——中心应用Host / Container。这个中心应用用于在线动态分发 Runtime 子模块它本身并不直接提供给用户使用而是作为其他应用的模块供给方存在。对微前端而言这种中心应用就是一个完美的主应用因为所有子应用都可以利用 Runtime 方式复用主应用的 Npm 包和模块从而更好地集成到主应用中。3 模块联邦实战ModuleFederationPlugin 配置与使用模块联邦本身是一个普通的 Webpack 插件——ModuleFederationPlugin在 Webpack5 中位于webpack/lib/container/ModuleFederationPlugin。3.1 插件四个核心参数ModuleFederationPlugin有几个重要参数理解它们是使用模块联邦的第一步参数含义关键点name当前应用名称需要全局唯一是其他应用引用本应用时的标识remotes远程依赖映射将其他项目的name映射到当前项目中声明我要消费哪些远程应用exposes导出模块清单只有在此声明的模块才可被作为远程依赖使用是暴露能力的白名单shared共享依赖清单最关键的参数声明后远程加载模块对应的依赖会改为使用本地项目的实例例如本地 React / ReactDOM避免重复加载与实例冲突其中shared是模块联邦实现公共依赖抽取的基石当你同时是 Provider 又是 Consumer 时shared让双方就同一份依赖如 React达成运行时共识——谁加载它、谁提供它、按需降级为各自的本地副本从而避免一个应用里有两份 React的经典问题。3.2 Host 应用消费方配置示例以下配置展示了如何在一个应用中同时消费另外两个远程应用app_two、app_three并暴露自己的模块给他人使用const HtmlWebpackPlugin require(html-webpack-plugin); const ModuleFederationPlugin require(webpack/lib/container/ModuleFederationPlugin); module.exports { // other webpack configs... plugins: [ new ModuleFederationPlugin({ name: app_one_remote, remotes: { app_two: app_two_remote, app_three: app_three_remote }, exposes: { AppContainer: ./src/App }, shared: [react, react-dom, react-router-dom] }), new HtmlWebpackPlugin({ template: ./public/index.html, chunks: [main] }) ] };解读要点name: app_one_remote本应用在联邦体系中的唯一标识remotes: { app_two: app_two_remote, ... }声明本应用会远程加载app_two与app_three冒号右侧的字符串如app_two_remote指向对方应用暴露的remoteEntry 全局变量名Webpack 在运行时通过它加载对方产出的remoteEntry.jsexposes: { AppContainer: ./src/App }本应用对外暴露AppContainer模块对应本地./src/Appshared: [react, react-dom, react-router-dom]声明 React 全家桶为共享依赖远程模块中的这些依赖会解析为本地实例。3.3 远程调用把对方模块当本地模块用配置了remotes之后代码中就可以直接以本地模块的方式从对方应用调用模块。例如设置了remotes: { app_two: app_two_remote }就可以直接写import { Search } from app_two/Search;这里的app_two/Search并不是本地文件而是指向远程应用app_two暴露出的Search模块。对引用方应用而言这个模块的使用体验与本地模块完全一致——这正是联邦的含义把分布在不同应用中的模块组织成一套可以被任意一方直接 import 的模块体系。3.4 Remote 应用提供方配置示例app_two/Search之所以能被引用是因为app_two在自己的 Webpack 配置中做了如下声明// app_two 的 webpack 配置 export default { plugins: [ new ModuleFederationPlugin({ name: app_two, library: { type: var, name: app_two }, filename: remoteEntry.js, exposes: { Search: ./src/Search }, shared: [react, react-dom] }) ] };与 Host 配置相比Remote 侧多了两个关键字段library: { type: var, name: app_two }将产出的远程模块以全局变量app_two的形式暴露供 Host 侧运行时通过remotes中配置的app_two_remote加载与对接。从模块联邦的实现机制看remotes右侧的字符串实际上就是这个全局变量名它通常与name或library.name保持一致是双方握手的关键契约filename: remoteEntry.js指定远程入口文件的名称。这个文件是模块联邦的特殊入口它不是标准的应用入口体积只有几 KB内部包含一段特殊的 Webpack runtime专门负责与 Host 应用对接、按需加载被暴露的模块。正是因为Search在exposes中被导出引用方才可以使用[name]/[exposes_name]这个模块语法而这个模块对于被引用应用Host来说就是一个本地模块——Webpack 在编译期解析、在运行时从远端拉取两者无缝衔接。4 模块联邦的运行时原理与中心应用形态4.1 特殊入口 remoteEntry.js上文提到remoteEntry.js是模块联邦的关键产物。它的特殊性在于它不是标准的应用入口不包含业务代码它只有几 KB 大小内部是一段特殊的 Webpack runtime它的职责是与 Host 的 runtime 交互Host 在运行时加载 remoteEntry通过它获取远程模块的清单并在真正import到对应模块时才去远端拉取对应的 chunk。也就是说模块联邦的模块加载是**按需Lazy**的Host 启动时只加载 remoteEntry 这个轻量契约真正的模块代码在用到时才通过网络加载配合 CDN 部署即可实现运行时热插拔。4.2 中心应用在线分发 Runtime 子模块模块联邦让应用具备模块化输出能力后自然衍生出一种新的应用形态——中心应用中心应用用于在线动态分发 Runtime 子模块并不直接提供给用户使用它可以被任意多个子应用在运行时拉取模块对微前端架构而言中心应用就是理想的主应用所有子应用都能以 Runtime 方式复用主应用的 Npm 包和模块实现依赖主应用提供、模块主应用分发的集成方式。这种中心应用 边缘子应用的拓扑让多项目之间的共享从构建期复制彻底走向运行期复用。4.3 共享依赖的运行时协调shared参数的价值在运行时体现得最明显当 Host 与 Remote 都声明共享 React 时Webpack 会生成一段**共享作用域shared scope**协商逻辑——从源码结构与社区实现看其核心是双方在运行时通过容器Container暴露各自的共享模块版本加载方优先使用对方或公共已加载的共享实例避免重复加载当版本不满足需求时再降级加载自己的本地副本。正是这种机制让模块联邦同时拿到了独立打包的解耦性与整体打包的依赖复用性这是 UMD 方案包体积无法优化、库易冲突无法做到的。5 总结与展望模块联邦为更大型的前端应用提供了开箱解决方案并已经作为 Webpack5 官方模块内置webpack/lib/container/ModuleFederationPlugin可以说是继 Externals 之后最终的运行时代码复用解决方案相比 NPM无需本地安装、重复构建产物可直接通过 CDN 共享相比 UMD保持构建产物优化能力Tree Shaking 等且依赖可共享不冲突相比微前端两种打包路线既保持子应用独立构建的扩展性又具备公共依赖抽取能力相比 Monorepo见 102.精读《Monorepo 的优势》Monorepo 解决的是源码聚合与复用的组织问题模块联邦解决的是构建产物跨应用运行时共享的部署问题两者互补。另外Webpack5 还内置了大量编译时缓存功能。可以看到无论是性能还是多项目组织Webpack5 都在尝试给出自己的最佳思路——从 47.精读《webpack4.0 升级指南》 的零配置演进到 5.0 的联邦模块与持久化缓存前端工程化正在迈向一个新的阶段。对于实际落地以下前提值得注意模块联邦需要 Webpack5 及以上版本支持配置与运行方式以当前 Webpack 版本的官方文档为准name需要全局唯一remotes右侧的全局变量名与 Remote 侧library.name必须严格对应exposes是白名单机制只有显式声明的模块才能被远程消费远程模块的部署依赖 CDN 或静态资源服务remoteEntry 与其分片 chunk 需要可被 Host 在运行时访问到。本文依据的原始精读文档位于 前沿技术/144.精读《Webpack5 新特性 - 模块联邦》.md其完整内容可在本仓库中继续查阅。赞分享文档技术博客教程【免费下载链接】weekly前端精读周刊。帮你理解最前沿、实用的技术。项目地址https://gitcode.com/GitHub_Trending/we/weekly点击查看免费下载相关推荐Razzle 集成 Webpack Module Federation双向联邦微前端实战with-module-federation 示例深度解析Razzle 集成 Webpack Module Federation双向联邦微前端实战with module federation 示例深度解析 本文基前端构建工具前端构建后端如何在3小时内完成一部10万字AI小说本地化部署完整指南如何在3小时内完成一部10万字AI小说本地化部署完整指南 想要创作一部完整的长篇小说却苦于灵感枯竭AI_NovelGenerator为你提供了完美的解决方案人工智能大模型AI 应用AI 写作RAG桌面应用Plop与Module Federation模块联邦的代码生成Plop与Module Federation模块联邦的代码生成 引言模块联邦的代码一致性挑战 在现代前端开发中Module Federation模块联邦开发工具CLI上一篇DeepTutor 完全指南从第一份 PDF 到你的 AI 个性化辅导助手下一篇参数调优秘籍提升LargeVis可视化效果的10个关键参数详解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表