微前端模块联邦实践系列(4) - subApp之间共享libraries

441 阅读3分钟

本系列大纲

在前面的例子中,我们采用了手撸的方式在页面中插入了3个节点。

在实际的开发中并不会像上述那么简单,我们会用到很多第三方库。如果每个项目中都引入了相同的三方库,势必会造成代码重复,加大了main的bundle体积,因此在某些情况下,我们需要将第三方库进行拆离,做成一个shared module来共享代码。

这篇文章主要来看看如何在subApp之间共享第三方库以及在引入相同模块的不同版本时是如何加载的?

我们本文中采用引入lodash为例。

配置shared模块 lodash

new ModuleFederationPlugin({
  // ...
  shared: ['lodash'],
})

使用相同的版本

  • container: lodash@4.17.21
  • subApp: lodash@4.17.21

打开localhost:8080,lodash模块只有一个版本,来源于posts。

vendor_lodash

使用lodash的不同major版本

  • container: lodash@3.10.1
  • subApp: lodash@4.17.21

打开localhost:8080,lodash模块会来源于两个subApp,分别是container以及posts。

lodash_two_parts

使用lodash的不同minor(patch)版本

  • container: lodash@4.17.20
  • subApp: lodash@4.17.21

打开localhost:8080,lodash模块只有一个版本,来源于posts。

vendor_lodash_2

强制使用相同的版本

  • container: lodash@3.10.1
  • subApp: lodash@4.17.21

配置singleton: true,强制使用相同模块的最高版本。

new ModuleFederationPlugin({
  // ...
  shared: [
    {
      lodash: {
        singleton: true,
        requiredVersion: false,
      },
    },
  ],
})

打开localhost:8080,lodash模块只有一个版本,来源于posts。

vendor_singleton

结论

  • 如果不同app中,使用相同模块的major版本不同,默认情况下会采用保留两个模块,分别加载
  • 如果不同app中,使用相同或者不同minor/patch版本,默认情况下则会合并成一个vendor,取版本最高的加载
  • 强制使用某个版本,在某些特殊情况下可能会出现问题,比如高版本不谦容低版本的某些api,在使用singleton的时候应该特别注意

shared dependencies

我们可以直接共享package.json中的所有denpendecies,让webpack module federation给我们自动生成所有共享模块的vendor。

// apps/container/config/webpack.dev.js (posts/albums 配置类似)

const packageJson = require('../package.json')

new ModuleFederationPlugin({
  // ...
  shared: packageJson.dependencies,
})

Subapp (posts/albums) 单独加载出现了问题?

在子subApp配置了shared之后,打开localhost:8081出现了问题,是什么原因?

posts_shared_error

然后我们可以打开network面板,切换到js

posts_load_async

发现应用本身在加载时,也load了remoteEntry.js,因此加载Shared module本身从同步变成了异步,所以我们要对subapp的加载采取和container类似的操作,新建bootstrap.js,将index.js的内容全部copy过去,然后在index.js中加载bootstrap

// apps/posts/src/index.js (albums类似)

import('./bootstrap')

修改exposes的导出文件

// apps/posts/config/webpack.dev.js

new ModuleFederationPlugin({
  name: 'posts',
  filename: 'remoteEntry.js',
  exposes: {
    './PostsIndex': './src/bootstrap',
  },
  shared: packageJson.dependencies,
})

重启webpack之后,就ok了。