webpack高级应用篇(十五):基于 Promise 的动态 Remote,让模块联邦版本化


静态 Remote 的问题

webpack高级应用篇(十三):模块联邦(Module Federation)- 未来组件包更新解决方案 最后的结语中有提到这样一句话:

试想一下,你有一个组件包通过npm发布后,你的10个业务项目引用这个组件包。当这个组件包更新了版本,你的10个项目想要使用最新功能就必须一一升级版本、编译打包、部署,这很繁琐。但是模块联邦让组件包利用CDN的方式共享给其他项目,这样一来,当你到组件包更新了,你的10个项目中的组件也自然更新了。是不是很香(*^▽^*)


事实上,我们在享受即时更新,减少繁琐的升级包版本、编译打包、部署的同时,也丢失了组件的版本化。这样会给项目带来风险,试想一下,如果你的一个组件有比较大的改动,当这个组件通过模块联邦暴露出去并被多个项目引用,那么这些项目都是存在风险的。因为你也许并没有进行对应项目线下测试,这些项目通过模块联邦得到的组件就被自动更新了,这很危险。


那么,有没有一个能解决版本化的方案呢?答案是肯定的。


基于 Promise 的动态 Remote

一般来说,remote 是使用 URL 配置的,示例如下:

module.exports = {
    
    
  plugins: [
    new ModuleFederationPlugin({
    
    
      name: 'app1',
      remotes: {
    
    
        App2: 'app2@http://localhost:3001/App2RemoteEntry.js',
      },
    }),
  ],
};

我们可以向 remote 传递一个 promise,其会在运行时被调用。使用任何符合 get/init 接口的模块来调用这个 promise。例如,如果你想传递你应该使用哪个版本的联邦模块,你可以通过一个查询参数做以下事情:


APP1

配置

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const {
    
     ModuleFederationPlugin } = require('webpack').container;

module.exports = {
    
    
  mode: 'development',
  entry: './src/index.js',
  output: {
    
    
    clean: true,
  },
  devtool: false,
  devServer: {
    
    
    port: '3000',
    client: {
    
    
      logging: 'none',
    },
  },
  plugins: [
    new HtmlWebpackPlugin(),

    new ModuleFederationPlugin({
    
    
      name: 'app1',
      remotes: {
    
    
        App3: `promise new Promise(resolve => {
          // TODO
          // 可以在这里设计和实现你的 模块联邦 版本化,这里简单的从URL获取version
          const urlParams = new URLSearchParams(window.location.search)
          const version = urlParams.get('app2VersionParam')
          console.log('version', version);
          const remoteUrlWithVersion = 'http://localhost:3001/' + version + '/App2RemoteEntry.js'
          console.log('remoteUrlWithVersion', remoteUrlWithVersion);
          const script = document.createElement('script')
          script.src = remoteUrlWithVersion
          script.onload = () => {
            // 注入的脚本已经加载并在window上可用
            // 我们现在可以解析这个Promise
            const proxy = {
              get: (request) => {
                console.log('request', request);
                return window.app2.get(request)
              },
              init: (arg) => {
                try {
                  console.log('arg', arg);
                  return window.app2.init(arg)
                } catch(e) {
                  console.log('remote container already initialized')
                }
              }
            }
            resolve(proxy)
          }
          // 将script的src设置为版本化的remoteEntry.js
          document.head.appendChild(script);
        })
       `,
      },
    }),
  ],
};

请注意当使用该 API 时,你 必须 resolve 一个包含 get/init API 的对象。


打包后

执行webpack

打包编译后如下,是可以在运行时执行的,因此你可以考虑将获取version的方式改为通过接口获取
在这里插入图片描述


APP2

配置

webpack.config.js

在发布前修改 filename

const HtmlWebpackPlugin = require('html-webpack-plugin');
const {
    
     ModuleFederationPlugin } = require('webpack').container;

module.exports = {
    
    
  mode: 'development',
  entry: './src/index.js',
  output: {
    
    
    clean: true,
  },
  devtool: false,
  devServer: {
    
    
    port: '3001',
    client: {
    
    
      logging: 'none',
    },
  },
  plugins: [
    new HtmlWebpackPlugin(),

    new ModuleFederationPlugin({
    
    
      // 模块联邦名字,提供给其他模块使用
      name: 'app2',
      // 提供给外部访问的资源入口
      filename: '1.0.0/App2RemoteEntry.js', // 在这里修改版本号
      // 引用的外部资源列表
      remotes: {
    
    },
      // 暴露给外部的资源列表
      exposes: {
    
    
        /**
         *  ./Header 是让外部应用的使用时基于这个路径拼接引用路径,如:nav/Header
         *  ./src/Header.js 是当前应用的要暴露给外部的资源模块路径
         */
        './Header': './src/Header.js',
      },
      // 共享模块,值当前被 exposes 的模块需要使用的共享模块,如lodash
      shared: {
    
    },
    }),
  ],
};

打包后

执行webpack,会得到新的文件

在这里插入图片描述


http://localhost:3000/?app2VersionParam=1.0.0

在这里插入图片描述


源码:https://gitee.com/yanhuakang/webpack-demos/tree/master/advanced/step_15-Module-Feder-Dynamic-Remote

猜你喜欢

转载自blog.csdn.net/qq_41887214/article/details/125962086