模块共享-webpack5模块联邦(Module Federation)

866 阅读10分钟

模块共享

模块共享(Module Sharing)是指在模块化的软件开发中,多个应用程序或模块之间共享代码、功能或资源的过程。通过模块共享,不同的应用程序可以重复使用已经开发和测试过的模块,从而提高开发效率、减少代码冗余,并促进代码的可维护性和可扩展性。

当前模块共享的处理方式

  1. npm方式公共模块共享

    使用第三方模块库是一种常见的模块共享方式。这些库通常包含常用的功能和工具,可以通过包管理器(如npm)进行安装和引用。开发人员可以通过引入这些库来获取所需的功能,避免从头编写代码。

    - 优点:大量的第三方模块可供选择,覆盖广泛的功能需求。通过包管理器安装和引用模块简单方便。

    - 缺点:有时可能需要依赖大量的第三方模块,增加了项目的依赖和复杂性。可能存在版本兼容性或安全性问题。

  2. UMD 方式共享模块

    为了实现内部的模块共享,组织或团队可以创建自己的内部模块库。这个库可以包含共享的代码模块、组件、工具类等。通过统一管理和维护内部模块库,不同的应用程序可以共享这些模块,并遵循一致的开发规范和最佳实践。

    - 优点:可以根据组织或团队的需求定制和维护模块,满足特定的业务需求。可以统一开发规范和最佳实践。

    - 缺点:需要额外的开发和维护成本。对于小团队或个人项目,可能不太实际。

  3. 微前端

    微前端通过将应用程序拆分为更小、更可管理的部分,使开发团队能够将其分解为独立的功能块,每个功能块都可以由不同的团队开发和维护。这些独立的功能块被称为微前端应用,它们可以是完全独立的应用程序,具有自己的技术栈、开发流程和部署策略

    -优点:

    1. 解耦和独立性:微前端允许将大型应用程序拆分为独立的功能块,每个功能块都可以由不同的团队开发和维护。这种解耦和独立性有助于减少团队之间的依赖和冲突。

    2. 技术栈灵活性:每个微前端应用可以选择适合自己的技术栈,不再局限于单一的前端框架或技术。这使得团队可以根据自身需求和技术偏好选择最适合的工具和技术。

    3. 增量升级和部署:微前端应用可以独立更新和部署,而不需要重新构建整个应用程序。这使得团队可以更快地推出新功能、修复错误和部署变更。

    4. 微服务化:通过将应用程序拆分为独立的微前端应用,可以更容易地扩展和管理应用程序的不同部分。每个微前端应用都可以独立扩展和调整,从而提高整个应用程序的可扩展性和可维护性。

    5. 提高团队效率:微前端模式允许各团队专注于自己负责的功能块,加快开发速度和部署周期。团队之间的协作和沟通也更加简化和灵活。

    -缺点:

    1. 架构设计复杂性:微前端模式需要进行合理的架构设计和组织,以确保各个微前端应用之间的协作和整体一致性。这需要对应用程序的拆分和集成进行仔细规划和管理。

    2. 共享资源管理:在微前端中,共享组件、样式和逻辑可能会变得更加复杂。确保共享资源的一致性和版本管理可能需要额外的努力。

    3. 运行时性能开销:微前端模式可能引入一些额外的运行时开销,例如加载和初始化多个微前端应用、路由切换等。这可能会对应用程序的性能产生一些影响,需要进行优化和性能测试。

    4. 浏览器兼容性:不同的微前端应用可能使用不同的前端框架、库和技术,这可能导致浏览器兼容性方面的挑战。确保微前端应用在各种浏览器和设备上正常运行可能需要额外的测试和调试工作。

  4. 模块联邦

    它允许在多个Webpack构建或应用程序之间动态共享JavaScript模块。不同的应用程序可以将特定的模块暴露给其他应用程序,使其能够按需使用这些共享模块,从而实现代码共享和模块化的架构。

    - 优点:动态共享模块,允许独立的应用程序协同工作。减少了代码重复和冗余,提高了开发效率和可维护性。支持灵活的模块加载和远程调用。

    - 缺点:需要使用Webpack 5及以上版本。配置和管理模块联邦可能会增加一些复杂性。在大型项目中,需要仔细考虑模块的拆分和共享策略。

模块共享的好处

  • 提高开发效率:通过重复使用已有的模块,减少了重复编写代码的工作量,提高了开发速度。

  • 降低维护成本:共享的模块经过开发和测试,可以提高代码的可靠性和稳定性,减少了维护代码的工作量。

  • 促进一致性:通过共享模块,不同的应用程序可以使用相同的代码实现相似的功能,从而确保了一致的行为和用户体验。

  • 支持团队协作:团队成员可以共享和理解共享模块,减少了团队之间的沟通成本,并促进协同开发。

总之,模块共享是一种重要的软件开发实践,它通过共享和重用代码模块来提高开发效率和代码质量。合理的模块共享策略可以帮助组织或团队更好地组织代码,并构建可维护和可扩展的应用程序。

选择适合的模块共享方式取决于项目的规模、团队的需求和技术栈。对于小型项目或临时性的共享,第三方模块库可能是最简单的选择。对于大型项目或组织内部的共享,建立内部模块库可以提供更高的灵活性和定制性。而模块联邦则适用于需要动态、跨应用程序的模块共享的复杂项目。

重要的是根据具体情况评估和选择最适合的模块共享方式。在进行共享之前,要考虑模块的可复用性、维护成本、团队协作和安全性等因素,以确保共享的模块能够提供预期的价值和效果。

四种模块共享方式对比

模块方式

定义

适用范围

优点

缺点

NPM

包管理器

package.json

Node.js

浏览器

易于使用和管理依赖项

增加应用程序的加载时间

更新流程繁琐

UMD

模块定义规范

旧版浏览器

需要在不同的模块系统中使用模块的场景。

兼容性好,可以在各种环境中使用

需要手动维护模块的定义和导出

微前端

架构风格

大型团队或组织,希望将前端应用程序进行模块化拆分和独立开发的场景

解耦、自治、独立开发和部署

需要额外的工程架构和管理成本

模块联邦

模块共享和动态加载的机制

需要将多个前端应用程序整合在一起,共享模块和资源的场景

灵活、高度可定制的模块共享方式

需要使用 Webpack 5 或更高版本,并需要进行相应的配置和管理

模块联邦

Webpack 5的模块联邦(Module Federation)是一个强大的功能,允许在多个webpack构建或应用程序之间动态共享JavaScript模块。它支持联邦式架构,让独立的应用程序能够无缝地合作和共享代码。

在Webpack 5中使用模块联邦,您可以创建一个主应用程序和一个或多个远程应用程序。主应用程序暴露要与远程应用程序共享的特定模块,而远程应用程序可以像使用自己的代码库一样使用这些共享模块。

用例

每个页面单独构建

单页应用的每个页面都是在单独的构建中从容器暴露出来的。主体应用程序(application shell)也是独立构建,会将所有页面作为远程模块来引用。通过这种方式,可以单独部署每个页面。在更新路由或添加新路由时部署主体应用程序。主体应用程序将常用库定义为共享模块,以避免在页面构建中出现重复。

将组件库作为容器

许多应用程序共享一个通用的组件库,可以将其构建成暴露所有组件的容器。每个应用程序使用来自组件库容器的组件。可以单独部署对组件库的更改,而不需要重新部署所有应用程序。应用程序自动使用组件库的最新版本。

配置

  1. 配置主应用程序:

    1. 为主应用程序配置Webpack配置。

    2. 使用Webpack配置中的**exposes**选项指定要向远程应用程序公开的共享模块。

  2. 配置远程应用程序:

    1. 为每个远程应用程序配置Webpack配置。

    2. 使用Webpack配置中的**remotes**选项指定远程应用程序要使用的共享模块。

  3. 构建和运行:

    1. 使用相应的Webpack配置构建主应用程序和远程应用程序。

    2. 将构建好的文件部署到适当的托管环境中。

    3. 在浏览器中加载主应用程序和远程应用程序。

在运行时,主应用程序动态加载远程应用程序,并从主应用程序获取共享模块。远程应用程序可以像使用本地模块一样使用这些共享模块。

模块联邦的使用

实践见repo.ehailiang.com:8088/89009814/mo…

host(vue2) 和mf-vue2 项目

webpack.config.js 分别配置模块联邦

  • name: 当前应用的名称,需要唯一性;

  • exposes: 需要导出的模块,用于提供给外部其他项目进行使用;

  • remotes: 需要依赖的远程模块,用于引入外部其他模块;

  • filename: 入口文件名称,用于对外提供模块时候的入口文件名;

  • shared: 配置共享的组件,一般是对第三方库做共享使用;

host应用

const { defineConfig } = require("@vue/cli-service");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    port: 8880,
  },
  publicPath: "http://localhost:8880/",
  configureWebpack: {
    plugins: [
      new ModuleFederationPlugin({
        name: "host",
        remotes: {
          remoteVue2: "remoteVue2@http://localhost:8881/remoteVue2.js",
        },
      }),
    ],
  },
});

<RemoteTest :title="title" @changeTitle="changeTitle" />
RemoteTest: () => import("remoteVue2/test")

remote应用

const { defineConfig } = require("@vue/cli-service");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    port: 8881,
  },
  publicPath: "http://localhost:8881/",
  configureWebpack: {
    optimization: {
      splitChunks: false,
    },
    plugins: [
      new ModuleFederationPlugin({
        name: "remoteVue2",
        filename: "remoteVue2.js",
        exposes: {
          "./app": "./src/App.vue",
          "./test": "./src/components/Test.vue",
        },
      }),
    ],
  },
});

注意点

  1. shared 不保证版本的一致性,会选取更高的版本

  2. host应用引入remote组件:原理:动态import

  3. module federation 官方Demo github.com/module-fede…

    1. vite-react-simple

    2. vue-cli

    3. vue2-in-vue3

    4. vue3-cli-demo

    5. vue3-demo-federation-with-vite

    6. vue3-demo

    7. ...

基于模块联邦的微前端解决方案 EMP

相关文章

EMP微前端分享内容回顾(上)

EMP微前端分享内容回顾(中)

EMP微前端分享内容回顾(下)

什么是微前端,可以带来什么价值

github github.com/efoxTeam/em…

掘金 juejin.cn/column/7019…