微前端实战

177 阅读2分钟

简介

Hello大家好,本篇文章主要向大家介绍一下如何使用微前端在项目中进行实际开发,此实战主要依赖在Angular中使用module-federation来实现,通过这篇文章希望大家可以学习到如何在Angular中实现Host和Remote的嵌套引用以及数据传输,组件渲染等。

Remote

  • 创建module,并在app-routing中export出来
  • 配置remote的web config文件
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 */1):

module.exports = {
output: {
    uniqueName: "piuistepperch",
    publicPath: "auto",
    scriptType: "text/javascript"}
optimization: {
    runtimeChunk: false
},
resolve:{
alias: {
 .. sharedHappings.getAltases()
 }
},
plugins: [
new ModuleFederationPlugin({
// For remotes (please adjust)
name: "remoteName",
filename: "testRemote.js",
exposes: {
'/testRemoteModule': "xx.module.ts'
},
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' 3},
"@angular/router": { singleton; true, strictversion: true, requiredVersion: 'auto' },
"@pi/common-lib": { singleton: true, requiredversion:
'auto' },
...shareMapping.getDescriptors()
})
... (if you want to export more modules we can refer above newxxplugin to add)

Host

首先我们在angular.json中需要已经配置好对应的解析文件

 "extraWebpackConfig": "webpack.config.js"

webpack.config.js

const ModuleFederationPlugin = require("webpack/lin/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 = t
output: {
uniqueName: "testUiHost";
publicPath: "/urlAddress(custom)",
scriptType: "text/javascript"},
optimization:

 runtimeChunk: false
},
resolve:{
alias:

 ...sharedMappings•getAliases(),
 }
}.
plugins: [
new ModuleFederationPlugin({
// For remotes (please adjust)
name: "paymentInitUiHost",
remotes:{},
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' }.
"@pi/common-lib": { singleton: true, requiredVersion: 'auto' }.
"ngx-localized-numbers": { singleton: true, requiredversion: 'auto' },
..sharedMappings•getDescriptors()
}),
sharedMappings getPlugin()

根据不同的环境配置不同的app-config文件,从而加载不同的remote module,以本地开发的config文件举例子

{
"production": false,
"errorRoute": "/error",
"redirectionURL": "xxxx",
"idleTime": "180",
"timeoutWarningTime":"120",
"remoteRoutes": [
  {
    "remoteKey": [
      {
       "uniqueName": "remoteName",
       "module": "testModule",
       "url": "http://localhost:4201/testRemoteEntry.js",
       "exposedModule": "./testModule"
       "path": "remoteKey",
       "purpose": "remoteRelevantModuleName"
      },
      ...
    ]
  }
]
}

解析上述config的文件

export calss ConfigService{
appConfig: = {
"production": false,
"errorRoute": "",
"redirectionURL": "",
"idleTime": "",
"timeoutWarningTime":"",
"remoteRoutes": []
 }
 
 async loadAppConfig(configURL: any) Promise<any> {
     const self = this;
     try {
       const response = await fetch(configURL);
       const config = await response.json();
       sessionStorage.setItem('config', JSON.stringify(config));
       self.appConfig = config;
     } catch (err) {
     console.log(err);
     }
 }
 
 public getRemote(): RemoteRoute{
  const moduleToLoad: = {};
  this.appConfig?.remoteRoutes.forEach((rrs) => {
   Object.entries(rrs).forEach(([key, value]) => {
    if(key !== method){return;}
    if(value && value.length > 0) {
    const remoteRoute = value.find((route) => route.purpose === purpose);
     moduleToLoad.uniqueName = remoteRoute?.uniqueName;
     moduleToLoad.exposeModule = remoteRoute?.exposeModule;
     moduleToLoad.url = remoteRoute?.url;
    }
   })
  })
  return moduleToLoad;
 }
}

在host中如何解析上边的文件去加载 remote module呢?我们有两种方式一种是通过html去渲染对应的remote module, 另外一种是通过url直接去加载remote module.

  • 通过html去渲染
<div *ngIf="remoteRoute?.url">
    <ng-conrainer
    appLoadRemote
    [remoteEntry]="remoteRoute?.url"
    [remoteName]="remoteRoute?.uniqueName"
    [exposedModule]="remoteRoute?.exposedModule"
</div>
 renderRemote(){
  this.remoteModule = this.configService.getRemote(params);
 }
  • 通过url去渲染
export class AppRoutingModule {
constructor(
@Inject ('APP_CONFIG') private apponfig: AppConfig,
private configservice: Configservice,
private router: Router){
const route = routes.find (route =› route-path === 'initial');
this.appConfig.remoteRoutes.forEach((rrs: RemoteRoutes) => {
const filteredRoutes = Object.values(rrs).map((rr: RemoteRoute[]) => rr.filter((r: RemoteRoute). => r.path)):
filteredRoutes.forEach((rrf: RemoteRoute[]) => {
rrf.forEach((r: RemoteRoute) => {
route. children.push(f
path: r.path, 
loadChildren:() => loadRemoteModule({
remoteName: r.uniqueName,
exposedModule: r.exposedModule,
remoteEntry: new URL(r.url+ deployVersion, window. location.origin).tostring()
}).then(m => m[r-module])
 .catch(e => console.log(e))
});
routes.push({
path:‘**’,
redirectTo: 'make-payment'
});
this.router.resetconfig(routes);

总结

微前端可以很好的运用在庞大项目上的开发, 各个remote独立出去可以进行项目的独立维护,至于host/remote之间的数据共享,事件通知这些都可以通过本地的webstorage,以及Rxjs进行封装实现,具体不过多赘述,希望这篇文章可以帮助大家对微前端架构有所了解。