让我们尝试使用Angular的模块联邦!!!

Module Federation是什么?

这是Webpack5的功能,可以在独立构建和部署的多个项目之间共享代码。通过设置一个中央的“联合体”模块,可以将其作为其他模块可以连接的中心枢纽运行。协作模块可以公开其代码的特定部分给其他协作模块,并像导入和使用自己项目的一部分一样使用该模块。这样,可以轻松地在多个项目之间共享通用代码,而无需在每个项目中复制该代码。

换句话说,这是一项非常酷的新技术,允许从一个独立的应用程序中公开和获取特定的组件,并传递给另一个独立的应用程序!

因为我在工作中使用了Module Federation,所以我想解释一下最简单的实现方法。
通常情况下,Module Federation就是指模块的共享,这是一个常见的情况,但我想讨论一下比较少涉及的组件的共享。

重点事项

Angular 15 (最好是提供方和获取方都使用相同的版本)
@angular-architects/module-federation 15.0.3

步骤

    1. 创建供应方和获取方的Angular项目。

 

    1. 两个项目中都使用ng add @angular-architects/module-federation@^15.0.3进行设置(ng add将为您自动完成设置,非常方便)。

 

    webpack.config.js将被自动创建。

在这里修改提供方的webpack.config.js。

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const mf = require("@angular-architects/module-federation/webpack");
const path = require("path");
const share = mf.share;

const sharedMappings = new mf.SharedMappings();
sharedMappings.register(
  path.join(__dirname, 'tsconfig.json'),
  [/* mapped paths to share */]);

module.exports = {
  output: {
    uniqueName: "remote",
    publicPath: "auto",
    scriptType: 'text/javascript'
  },
  optimization: {
    runtimeChunk: false
  },   
  resolve: {
    alias: {
      ...sharedMappings.getAliases(),
    }
  },
  experiments: {
    outputModule: true
  },
  plugins: [
    new ModuleFederationPlugin({
        //library: { type: "module" },

        // For remotes (please adjust)
        name: "remote",
        filename: "remoteEntry.js",
        exposes: {
            './Component': './src/app/remote/remote.component.ts',
        },        
        
        // For hosts (please adjust)
        // remotes: {
        //     "mfe1": "http://localhost:3000/remoteEntry.js",

        // },

        shared: share({
          "@angular/core": { singleton: true, strictVersion: true, requiredVersion: 'auto' }, 
          "@angular/common": { singleton: true, strictVersion: true, requiredVersion: 'auto' }, 
          "@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: 'auto' }, 
          "@angular/router": { singleton: true, strictVersion: true, requiredVersion: 'auto' },

          ...sharedMappings.getDescriptors()
        })
        
    }),
    sharedMappings.getPlugin()
  ],
};

重点是将scriptType: ‘text/javascript’添加进去,将library: { type: “module” }注释掉。

只需要设置以下提供的组件路径即可!(./Component:部分可以自己决定)

        name: "remote",
        filename: "remoteEntry.js",
        exposes: {
            './Component': './src/app/remote/remote.component.ts',
        }

提供方的设置已经完成了。非常简单!

接下来我们将修改接收方的 webpack.config.js。

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const mf = require("@angular-architects/module-federation/webpack");
const path = require("path");
const share = mf.share;

const sharedMappings = new mf.SharedMappings();
sharedMappings.register(
  path.join(__dirname, 'tsconfig.json'),
  [/* mapped paths to share */]);

module.exports = {
  output: {
    uniqueName: "host",
    publicPath: "auto",
    scriptType: 'text/javascript'
  },
  optimization: {
    runtimeChunk: false
  },   
  resolve: {
    alias: {
      ...sharedMappings.getAliases(),
    }
  },
  experiments: {
    outputModule: true
  },
  plugins: [
    new ModuleFederationPlugin({
        //library: { type: "module" },

        // For remotes (please adjust)
        // name: "host",
        // filename: "remoteEntry.js",
        // exposes: {
        //     './Component': './/src/app/app.component.ts',
        // },        
        
        // For hosts (please adjust)
        remotes: {
            "remote": "remote@http://localhost:4200/remoteEntry.js",

        },

        shared: share({
          "@angular/core": { singleton: true, strictVersion: true, requiredVersion: 'auto' }, 
          "@angular/common": { singleton: true, strictVersion: true, requiredVersion: 'auto' }, 
          "@angular/common/http": { singleton: true, strictVersion: true, requiredVersion: 'auto' }, 
          "@angular/router": { singleton: true, strictVersion: true, requiredVersion: 'auto' },

          ...sharedMappings.getDescriptors()
        })
        
    }),
    sharedMappings.getPlugin()
  ],
};

与提供者相同,添加 scriptType: ‘text/javascript’ 并将 library: { type: “module” 进行注释。

这次只需要设置获取供应名称和地址(remoteEntry.js)。

        remotes: {
            "remote": "remote@http://localhost:4200/remoteEntry.js",
        },

让我们最后来实际获取组件并进行渲染。

import { loadRemoteModule } from '@angular-architects/module-federation';
import {
  Component,
  ComponentFactoryResolver,
  OnInit,
  ViewContainerRef,
} from '@angular/core';
import { RemoteCompDirective } from './remote-comp.directive';

@Component({
  selector: 'app-root',
  template: ``,
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {

  constructor(
    private componentFactoryResolver: ComponentFactoryResolver,
    private viewContainerRef: ViewContainerRef
  ) {}

  ngOnInit(): void {
        loadRemoteModule({
          remoteEntry: 'http://localhost:4200/remoteEntry.js',
          remoteName: 'remote',
          exposedModule: './Component',
        }).then((m) => {
          const { RemoteComponent } = m;
          const componentRef = this.viewContainerRef.createComponent(
            this.componentFactoryResolver.resolveComponentFactory(RemoteComponent)
          );
        });
    }
}

只要指定提供的组件名称,就可以直接获取!太棒了!最好的是,提供方组件的变更会立即反映到获取方!这使得在制作一个应用程序的同时,还可以同时开发另一个应用程序的功能!这么简单地进行并行开发!太好了!

以上! !)

以上!

如果有任何问题、建议等,请随意提出!好了!

bannerAds