webpack 公共库-umi 使用 webpack5 模块联合

前言

最近在做微后端开发。 当我遇到子应用程序资源问题而无法共享时,我了解到webpack5可以动态运行另一个JavaScript应用程序的代码,同时共享一个依赖项。 由于框架使用Umi进行开发,官方没有提供配置示例。 如果您在使用过程中遇到一些陷阱,请记录下来。

模块联盟

Module Federation 中文直译为“模块联邦”。 在webpack官方文档中,实际上并没有给出它的真正含义,但是给出了使用这个功能的动机。

多个独立的构建可以形成一个应用程序。这些独立的构建不会相互依赖,因此可以单独开发和部署它们。
这通常被称为微前端,但并不仅限于此

Webpack 配置模块联合

  const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
  module.exports = {
    // 其他webpack配置...
    plugins: [
      new ModuleFederationPlugin({
          name: 'app',
          library: { type: 'umd', name: 'app' },
          filename: 'app.js',
          remotes: {
            app_1: "app_1_remote",
            app_2: "app_2_remote"
          },
          exposes: {
            './Button': 'src/components/Button',
            './Component2': 'src/components/Component2',
          },
          shared: ["react", "react-dom"]
        })
    ]
  }

通过上面的配置,我们对mf有了一个初步的了解,也就是说,如果我们想要使用mf,我们需要配置几个重要的属性:

字段名称 类型 含义

姓名

细绳

所需的值是输出模块名称。 远程引用时,路径为name/{name}/name/{expose}

图书馆

细绳

声明全局变量的方法webpack 公共库,名称为umd的名称

文件名

细绳

构建输出的文件名

遥控器

目的

映射远程引用的应用程序名称及其别名,使用时使用键值作为名称

暴露

目的

远程引用时可以公开的资源路径及其别名

共享

目的

可以与其他应用程序共享的第三方依赖项,无需在代码中重复加载相同的依赖项

umi框架使用

首先我们通过脚手架创建两个项目,分别是mf1,端口3000,导出一些组件Button等,项目mf2,端口3001,引入mf1的Button组件。我们看一下mf1的配置

项目 mf1 配置

我们项目mf1的主要功能是提供MF能力并导出Button组件以供其他应用程序使用。

const { ModuleFederationPlugin } = require("webpack").container;
export default defineConfig({
  // 其他umi配置...
  publicPath:'//localhost:3000/',
  webpack5: {},
  chainWebpack(memo) {
    memo
      .plugin('mf')
      .use(ModuleFederationPlugin, [{
        name: "mf1",
        library: { type: 'umd', name: 'mf1' },
        filename: 'remoteEntry.js',
        exposes: {
          "./Button": './src/components/button/index',
        },
        shared: { react: { eager: true }, "react-dom": { eager: true } }
      }])
  },
});

这里的 umi 配置中,需要启用 webpack5 并添加 publicPath。 特别注意配置publicPath。 如果不配置,其他应用程序将无法加载导入的模块。

按钮组件

import React, { FC } from 'react';
const Button = props => {
  return (<div><button>我是mf1的button</button></div>);
}
export default Button;

项目 mf2 配置

我们项目mf2的主要功能是提供MF能力webpack 公共库,为当前应用引入远程mf1应用组件。

中频配置

const { ModuleFederationPlugin } = require("webpack").container;
export default defineConfig({
 // 其他umi配置...
  webpack5: {},
  dynamicImport:{},
  chainWebpack(memo) {
    memo
      .plugin('mf')
      .use(ModuleFederationPlugin, [{
        name: "mf2",
        remotes: {
          mf1: "mf1@//localhost:3000/remoteEntry.js"
        }
        shared: { react: { eager: true }, "react-dom": { eager: true } }
      }])
  },
});

这里的umi配置中,需要启用webpack5并添加dynamicImport。 特别注意配置dynamicImport,避免报错。

使用 mf1 项目组件

由于mf提供了异步加载,所以在使用组件时我们不得不依赖React的React.lazy和React.Suspense来加载异步组件。

// 导入组件
const Mf1Button = React.lazy(() => import("mf1/Button"));
export default function IndexPage() {
  return (
    <div>
      <React.Suspense fallback='loading'>
        <Mf1Button />
      </React.Suspense>
    </div>
  );
}

配置说明 Umi 框架使用问题

通过上面的简单配置,我们运行了M​​F,但是出现了以下问题:

解决公共路径

通过查看MF文档,publiPath可以是auto。 它将手动为您确定一个 publicPath。 但如果我们直接配置的话,就会出错。 umi 框架会验证是否以 / 开头,以符合 publicPath 规则。我们尝试修改 webpack 方法来解决问题,配置为

chainWebpack(memo) {
    memo.output.publicPath('auto');
    // 其它webpack配置
  },

使用webpack。问题已经解决。 至此,部署问题已经解决。

解决组件中无法使用Hooks的问题

MF一定要记得加共享。 这个配置可以为我们共享依赖。为了解决这个问题,官方要求我们设置异步导出的入口,参考链接

但 umi 不支持异步启动。 我们可以通过编写插件来支持功能和插件内容。

import { IApi } from 'umi';
import { resolve } from 'path';
import { readFileSync } from 'fs';
export default (api: IApi) => {
  api.onGenerateFiles(() => {
    const buffer= readFileSync(resolve('./src/.umi/umi.ts'))
    const c = String(buffer)
    // console.log()
    api.writeTmpFile({
      path: 'index.ts',
      content: c,
    });
    api.writeTmpFile({
      path: 'umi.ts',
      content: 'import("./index")',
    });
  });
};

主要是先获取 umi 生成的入口文件。 我们自己创建一个文件,将内容写入其中,然后更改入口文件的内容。 我已经制作了一个 npm 包。 您可以直接使用它。 该插件名为 umi-plugin-mf-bootstrap,我们只安装yarn install umi-plugin-mf-bootstrap。重启项目,umi 会手动加载插件

结论

至此我们就完成了 umiModule Federation 的使用。 我们在制作微后端的时候也使用了qiankun和umi的qiankun-plugin插件。 我们写的 umi-plugin-mf-bootstrap 会不兼容,不能同时使用。 我们也在积极探索,如果有进展就会发布。

参考链接

MF-演示

umi-插件-mf-bootstrap

模块联盟

umi 插件

如果您觉得文章不错,不妨点个关注

1.点赞,让更多人看到此内容