65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 ModuleFederationPlugin 引入微前端

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2022年11月11日

CPOL

6分钟阅读

viewsIcon

7299

MFE 概览以及 Module Federation Plugin 如何帮助在 React 中构建 MFE。

引言

本文为您介绍 Module Federation Plugin,并提供对 ModuleFederationPlugin 的基本理解。

我们将讨论以下内容:

  • 为什么我们需要 MFE(微前端)
  • 什么是 MFE(微前端)
  • 如何构建 MFE(微前端)

背景

让我们通过一个故事来理解“为什么”。Amey 住在印度 Thane。Thane 以湖泊之城而闻名。一天,Amey 想开始他的手机销售业务。他决定在 Thane 的三个热门地点开设 3 家商店。第一家是 Thane-Highway,第二家是 Thane-Lake,最后但同样重要的是 Thane-University。嗯…… 这是个非常好的想法。在开店之前,他运行了一个服务器,并注意到 Thane-Highway 对三星手机有需求,Thane-Lake 对 iPhone 手机有需求,Thane-College 对三星和 iPhone 都有需求。Amey 决定开设 3 家商店并为其建立一个网站。

第一家店为顾客提供三星手机列表。
第二家店为顾客提供 iPhone 手机列表。
第三家店为顾客提供 iPhone 和三星手机列表。

像其他商人一样,他想尽快推出网站,于是他打电话给朋友,请他帮忙构建网站。他的朋友提出了两种方法。请注意,我们所有的应用程序都是假的,没有后端集成。

1) 构建单体应用程序

这种方法本身很好,但可能会有一个团队构建整个应用程序,并且随着业务增长和品牌增多,网站会变得越来越复杂,难以扩展和修改,因为组件之间存在紧密耦合。此外,网站会绑定到像 React 或 Vue 等语言。如果将来我们想用不同的语言编写未来的代码,那么这方面的空间很小,并且将主要需要重写整个网站。

2) 构建(MFE)微前端架构

什么是 MFE?

微前端 帮助我们将大型前端应用程序分解成更小、独立的应用程序或模块。
每个更小的应用程序或模块负责应用程序的特定功能。
我们可以拥有独立的工程团队来负责应用程序的每个不同功能。
每个更小的应用程序都易于理解和修改。

构建时集成

这可以通过构建三星手机的 Node 包和 iPhone 手机的 Node 包,并通过 NPM(Node 包管理器)发布来实现。然后构建一个消耗它们的宿主应用程序。这看起来更好。由于这些 Node 包在加载宿主应用程序到浏览器或源代码被编译之前就被下载并且源代码被暴露出来,因此这种方法被称为构建时集成。

运行时集成

这可以通过将每个域(例如,三星手机和 iPhone 手机)构建成一个单独的 SPA(单页应用程序),称为远程应用程序来实现。然后构建一个宿主应用程序来托管这些远程应用程序。当您运行宿主应用程序时,它会下载远程源代码并访问它。这种集成被称为运行时集成。

注意:如果您此时还没有理解,请不要担心,请继续跟着我。

我们如何实现这一点?

这可以使用 webpack 5 及以上版本提供的 ModuleFederationPlugin 来轻松实现。

让我带您进入故事的“如何”部分,这开始变得有趣起来。下载附带的代码。它包含三个应用程序。三星和 iPhone 是远程应用程序,amey-store 是宿主应用程序。

什么是远程应用程序?

这些应用程序允许您与宿主应用程序共享不同的功能(代码)。

什么是宿主应用程序?

此应用程序控制何时何地显示远程应用程序共享的特定功能。

远程应用程序演练。打开三星应用程序。您会注意到一个简单的 Node 应用程序,其中包含 mobilelist.js,它加载虚假的手机列表,并通过 index.js 进行托管,其中 index.js 加载到 index.html 文件中的 s-mobile 列表 div。核心部分是 webpack.config。如果您打开 webpack.config,您会注意到以下代码。

const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
    new ModuleFederationPlugin({
      name: 'samsungmobiles',
      filename: 'remoteEntry.js',
      exposes: {
        './ShowMobiles': './src/index',
      },
    }),

远程应用程序的 ModuleFederationPlugin 可以使用三个重要选项进行配置:namefilenameexposes

  • name:远程应用程序必须有一个名称,宿主应用程序可以引用该名称。
  • filenamewebpack 创建的捆绑文件,宿主应用程序可以下载该文件。
  • exposes:我们希望与宿主共享代码的组件。我们可以为暴露的组件提供别名,这是一个有意义的名称,可以在宿主应用程序中导入。如果宿主应用程序请求 ShowMobiles,它会从 src 文件夹中返回 index 文件。

宿主应用程序演练。打开 amey-store 宿主项目。宿主应用程序的 ModuleFederationPlugin 可以使用 remotes 选项进行配置,其中 name 是可选的,但为了清晰起见,最好给出。

remotes 宿主可以搜索以获取其他代码的项目列表。考虑以下代码,如果我们有 import { abc } from 'samsungmobiles'。然后 webpack 在 Node 模块中搜索 samsungmobiles 组件,如果找不到,它会进入 ModuleFederationPluginremotes 对象中检查。现在,如果我想这样导入它:import { abc } from 'samsungmobilesApp',那么我可以重命名我的远程入口点为

remote: { samsungmobilesApp: ''samsungmobiles@https://:8081/remoteEntry.js'' }

remotes 属性的值是“引用名称 @远程 URL”。引用名称就是远程应用程序中ModuleFederationPlugin的名称。然后是宿主应用程序下载 remoteEntry.js 文件的 URL。

new ModuleFederationPlugin({
      name: 'container',
      remotes: {
        samsungmobiles: 'samsungmobiles@https://:8081/remoteEntry.js',
      },
    })

让我们详细了解一下它是如何工作的。打开 bootstrap.js。您会注意到以下代码。

import 'samsungmobiles/ShowMobiles';
console.log('Host!');

我们的 index.js异步模式加载 bootstrap.jsimport('./bootstrap')。当 bootstrap.js 加载完成后,它会找到 import 语句并尝试在 Node 模块文件夹中搜索包。如果它在 Node 模块文件夹中找不到该包,它将进入 ModuleFederationPlugin 并在远程部分搜索 samsungmobiles。当它找到时,它会从指定的 URL 下载 remoteEntry.js。如果您问到我们例子中 @符号前的名称“samsungmobiles@https://:8081/remoteEntry.js”有什么用。如果您打开 remoteEntry.js,它有一个变量名 samsungmobiles,它暴露了远程应用程序共享的代码。让我们将其更改为 samsungmobilesApp,如下所示:

remotes: { samsungmobiles: 'samsungmobilesApp@https://:8081/remoteEntry.js', }, 

代码会中断,这可以通过更改远程应用程序(三星应用程序)的 ModuleFederationPlugin 名称为 samsungmobilesApp 来修复。当我们加载组件 ShowModbiles 时,它的所有依赖项也会一起加载。在我们的例子中,我们使用 faker 模块来获取手机名称。由于两个应用程序都使用相同版本的 faker,我们可以将其定义为共享依赖项。即,宿主应用程序只能加载一个依赖项副本并与所有远程应用程序共享。

 new ModuleFederationPlugin({
      name: 'container',
      remotes: {
        samsungmobiles: 'samsungmobiles@https://:8081/remoteEntry.js',
      },
      shared: ['faker'],
    })

宿主应用程序可能正在使用某个依赖项,例如 React 包,并期望所有远程应用程序都使用相同的版本。在这种情况下,依赖项可以被指定为单例。下面的代码强制所有远程应用程序运行在 faker 版本 5.1.0 上。

 new ModuleFederationPlugin({
      name: 'container',
      remotes: {
        samsungmobiles: 'samsungmobiles@https://:8081/remoteEntry.js',
      },
      faker: {
        requiredVersion: '5.1.0',
        singleton: true,
      },
    }),

注意:我们例子中第二个远程应用程序(iPhone 应用程序)的代码未给出。您可以将其与三星应用程序的代码一样复制,作为自我练习。

关注点

本文介绍了使用 ModuleFederationPlugin 进行 MFE。请保持关注。我将在下一篇文章中讨论状态管理、身份验证和 CSS 处理的高级概念。

历史

  • 2022年11月10日:初始版本
© . All rights reserved.