如何使用模块联合动态访问 vue js 中的远程组件

How to dynamically access a remote component in vue js with module federation

我正在尝试使用模块联合构建一个 vue js 2 微前端。我不想像这样

通过 webpack.config.js 使用静态远程导入
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'host',
      remotes: {
        app1: 'app1@http://localhost:3001/remoteEntry.js',
      },
    }),
  ],
};

我正在寻找一种将 vue 组件动态导入到我的主机应用程序中的方法。到目前为止,我尝试了 this 方法,但我只找到了适用于 angular 或反应的示例。

目标是拥有多个远程前端,可以自动在某处注册,也许在某种商店中。然后主机应用程序可以访问此存储并获取所有已注册的远程应用程序(名称、url、组件)。然后主机应用程序加载组件并且应该能够使用它们。我远程导入组件 HelloDerp,加载过程工作正常,但我不知道如何在我的主机应用程序上呈现它。我阅读了有关动态和异步导入的 vue js 文档,但我认为这仅适用于本地组件。 到目前为止,我在主机应用程序中得到了什么:

<template>
  <div id="app">
    <HelloWorld />
    <HelloDerp />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";
const HelloDerp = null;


export default {
  name: "App",
  components: {
    HelloWorld,
    HelloDerp,
  },
  mounted() {
    var remoteUrlWithVersion = "http://localhost:9000/remoteEntry.js";
    const element = document.createElement("script");

    element.type = "text/javascript";
    element.async = true;
    element.src = remoteUrlWithVersion;
    element.onload = () => {
      console.log(`Dynamic Script Loaded: ${element.src}`);
      HelloDerp = loadComponent("core", "./HelloDerp");
    };

    document.head.appendChild(element);

    return null;
  },
};

async function loadComponent(scope, module) {
  // Initializes the shared scope. Fills it with known provided modules from this build and all remotes
  await __webpack_init_sharing__("default");
  const container = window[scope]; // or get the container somewhere else
  // Initialize the container, it may provide shared modules
  await container.init(__webpack_share_scopes__.default);
  const factory = await window[scope].get(module);
  const Module = factory();
  return Module;
}
</script>

抱歉,我差点忘了这件事。这是我的解决方案。

加载模块:

export default async function loadModules(
  host: string,
  ownModuleName: string,
  wantedNames: string[]
): Promise<RemoteComponent[]> {
    ...
    uiApplications.forEach((uiApplication) => {
      const remoteURL = `${uiApplication.protocol}://${uiApplication.host}:${uiApplication.port}/${uiApplication.moduleName}/${uiApplication.fileName}`;

      const { componentNames } = uiApplication;
      const { moduleName } = uiApplication;
      const element = document.createElement('script');
      element.type = 'text/javascript';
      element.async = true;
      element.src = remoteURL;

      element.onload = () => {
        componentNames?.forEach((componentName) => {
          const component = loadModule(moduleName, `./${componentName}`);

          component.then((result) => {
            if (componentName.toLowerCase().endsWith('view')) { 
            // share views
              components.push(new RemoteComponent(result.default, componentName));
            } else { 
            // share business logic
              components.push(new RemoteComponent(result, componentName));
            }
           });
        });
      };
      document.head.appendChild(element);
    });
  });
  ...
}

export default async function loadModule(scope: string, module: string): Promise<any> {
  await __webpack_init_sharing__('default');
  const container = window[scope]; // or get the container somewhere else
  await container.init(__webpack_share_scopes__.default);
  const factory = await window[scope].get(module);
  const Module = factory();
  return Module;
}

将模块添加到路由

 router.addRoute({
        name: remoteComponent.componentName,
        path: `/${remoteComponent.componentName}`,
        component: remoteComponent.component,
  });