如何在组件中直接使用联邦代码(Angular模块联邦)

huangapple go评论57阅读模式
英文:

How to consume federated code directly in a component (Angular Module Federation)

问题

以下是您要翻译的内容:

我在主应用程序中使用了一个远程的联邦微前端组件,当它在应用程序的路由中使用时可以正常工作:

path: 'panel',
loadChildren: () => loadRemoteModule({
    type: 'module',
    remoteEntry: 'http://localhost:4201/remoteEntry.js',
    exposedModule: './Module',
}).then(m => m.MainPanelModule)

这是MFE/远程Webpack配置:

module.exports = withModuleFederationPlugin({
  name: 'mainPanel',
  exposes: {
    './Module': './src/main-panel/main-panel.module.ts',
  },

  shared: {
    ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto', eager: true }),
  },
});

这是主应用程序Webpack配置:

new ModuleFederationPlugin({
        remotes: {
          mainPanel: 'http://localhost:4201/remoteEntry.js'
        },
        shared: share({
          "@angular/core": { requiredVersion: 'auto', eager: true },
          "@angular/common": { requiredVersion: 'auto', eager: true },
          "@angular/common/http": { requiredVersion: 'auto', eager: true },
          "@angular/router": { requiredVersion: 'auto', eager: true },
        })

    }),

这些配置在http://localhost:4200/panel上工作得很好,我可以看到远程的MFE组件。但是,我需要直接从应用程序的另一个组件中使用它,而不是从路由中。例如,在HTML中,如下所示:

<main-panel></main-panel>

我该如何做到这一点?我使用的是Angular 14,刚刚升级,目前还不能升级到下一个版本。

我已经阅读了关于在Angular中使用Module Federation实现微前端的各种文章,但几乎所有这些文章都提供了从路由中使用远程组件的示例。我找到了一个文章中他们讨论了一个潜在的解决方案,但他们使用了另一个库,我需要在不添加任何新库的情况下完成它(如果可能的话)。这是否可以实现?

英文:

I have a federated micro frontend remote component consumed in my main application, that works when it's consumed in the application routes:

path: &#39;panel&#39;,
 loadChildren: () =&gt; loadRemoteModule({
     type: &#39;module&#39;,
     remoteEntry: &#39;http://localhost:4201/remoteEntry.js&#39;,
     exposedModule: &#39;./Module&#39;,
 }).then(m =&gt; m.MainPanelModule)

Here is the MFE/remote webpack config:

module.exports = withModuleFederationPlugin({
  name: &#39;mainPanel&#39;,
  exposes: {
    &#39;./Module&#39;: &#39;./src/main-panel/main-panel.module.ts&#39;,
  },

  shared: {
    ...shareAll({ singleton: true, strictVersion: true, requiredVersion: &#39;auto&#39;, eager: true }),
  },
});

And here is the main application webpack config:

new ModuleFederationPlugin({
        remotes: {
          mainPanel: &#39;http://localhost:4201/remoteEntry.js&#39;
        },
        shared: share({
          &quot;@angular/core&quot;: { requiredVersion: &#39;auto&#39;, eager: true },
          &quot;@angular/common&quot;: { requiredVersion: &#39;auto&#39;, eager: true },
          &quot;@angular/common/http&quot;: { requiredVersion: &#39;auto&#39;, eager: true },
          &quot;@angular/router&quot;: { requiredVersion: &#39;auto&#39;, eager: true },
        })

    }),

These configs work just fine - when I go to http://localhost:4200/panel I can see the remote mfe component. However, I need to consume it directly from another component in the application, not from the routes. For example, in the html, like so:

&lt;main-panel&gt;&lt;/main-panel&gt;

How can I do that? I am on Angular 14, just upgraded, and I can't go to the next version yet.

I have read various articles on the topic of Micro Frontend Implementation with Module Federation in Angular, but almost all of them are providing an example of consuming the remote from the routes. I found one article where they discuss a potential solution, but they are using another library, and I need to do it without adding any new libraries (if possible). Can this be done?

答案1

得分: 0

以下是翻译好的部分:

对于仍在尝试弄清楚这一点的任何人,我使用ViewChild获取了HTML,然后在代码中使用loadRemoteModule方法获取remoteEntry.js文件:

ts文件:

@ViewChild('placeHolder', { read: ViewContainerRef }) viewContainer!: ViewContainerRef;

ngOnInit() {
    this.loadRemote();
}

async loadRemote(): Promise<void> {
    const m = await loadRemoteModule({
        type: 'module',
        remoteEntry: 'http://localhost:4201/remoteEntry.js',
        exposedModule: './Component'
    });
    const componentRef = this.viewContainer.createComponent(m.MainPanelComponent);
}

HTML文件:

<template #placeHolder></template>

当您在本地运行您的MFE时,这可以正常工作,但如果您将其发布到S3(而且它不在公共存储桶中),您可以使用Express路由创建自己的端点,并在后台执行S3逻辑。我的方法使用AWS SDK for S3的getObject方法(而不在本地运行MFE)也能正常工作。但是,如果您的S3存储桶是公共的,您可以将localhost URL替换为S3的URL,我相信应该可以。

更新:

如果出现“此浏览器不支持自动公共路径”的浏览器控制台错误,请确保将tsconfig编译选项中的目标设置为“es2020”。

英文:

For anyone still trying to figure this out, I got the html using viewChild and then used the loadRemoteModule method in the code to get the remoteEntry.js file:

ts file:

@ViewChild(&#39;placeHolder&#39;, { read: ViewContainerRef }) viewContainer!: ViewContainerRef;

ngOnInit() {
      this.loadRemote();
}

async loadRemote(): Promise&lt;void&gt; {
      const m = await loadRemoteModule({
              type: &#39;module&#39;,
              remoteEntry: &#39;http://localhost:4201/remoteEntry.js&#39;,
              exposedModule: &#39;./Component&#39;
          });
          const componentRef = this.viewContainer.createComponent(m.MainPanelComponent);
  }

html file:

&lt;template #placeHolder&gt;&lt;/template&gt;

This works when you are running your MFE locally, but if you are publishing it to S3 (and it's not in a public bucket), you can create your own endpoint using Express router, and do the S3 logic in the background. Mine works using the getObject method from AWS SDK for S3 (without running the MFE locally). If your S3 bucket is public however, you can just replace the localhost URL with the S3 one, I believe.

UPDATE:

If you hit an "Automatic publicPath is not supported in this browser" browser console error, make sure to set target to "es2020" in your tsconfig compiler options.

huangapple
  • 本文由 发表于 2023年4月20日 07:27:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76059515.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定