让我们尝试使用Angular的模块联邦!!!
Module Federation是什么?
这是Webpack5的功能,可以在独立构建和部署的多个项目之间共享代码。通过设置一个中央的“联合体”模块,可以将其作为其他模块可以连接的中心枢纽运行。协作模块可以公开其代码的特定部分给其他协作模块,并像导入和使用自己项目的一部分一样使用该模块。这样,可以轻松地在多个项目之间共享通用代码,而无需在每个项目中复制该代码。
换句话说,这是一项非常酷的新技术,允许从一个独立的应用程序中公开和获取特定的组件,并传递给另一个独立的应用程序!
因为我在工作中使用了Module Federation,所以我想解释一下最简单的实现方法。
通常情况下,Module Federation就是指模块的共享,这是一个常见的情况,但我想讨论一下比较少涉及的组件的共享。
重点事项
Angular 15 (最好是提供方和获取方都使用相同的版本)
@angular-architects/module-federation 15.0.3
步骤
-
- 创建供应方和获取方的Angular项目。
-
- 两个项目中都使用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)
);
});
}
}
只要指定提供的组件名称,就可以直接获取!太棒了!最好的是,提供方组件的变更会立即反映到获取方!这使得在制作一个应用程序的同时,还可以同时开发另一个应用程序的功能!这么简单地进行并行开发!太好了!
以上! !)
以上!
如果有任何问题、建议等,请随意提出!好了!