You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过模块联邦从Shell项目程序化引导MFE的路由、NgRx等?

程序化引导MFE的路由、NgRx及依赖配置方案

针对你在Shell中懒加载MFE模块时,需要确保所有必要配置(路由、NgRx实例等)完整加载初始化的需求,以下是几种实用实现方式:

1. 扩展模块加载后的初始化钩子

让MFE模块暴露专门的初始化函数,Shell在加载模块后手动触发,将Shell侧的核心依赖(如NgRx Store、Router)传入,由MFE自主完成配置注册。

MFE侧实现

在MFE的模块文件中导出初始化逻辑:

// MFE/src/app/my-sub/my-sub.module.ts
import { Store } from '@ngrx/store';
import { Router } from '@angular/router';
import { registerTodoFeature } from './store/todo.feature';
import { todoRoutes } from './todo.routes';

// 暴露给Shell的初始化函数
export function initMfeDependencies(store: Store, router: Router) {
  // 注册NgRx Feature Store
  registerTodoFeature(store);
  // 动态添加MFE路由到Shell路由表
  router.config.unshift(...todoRoutes);
  // 其他第三方库初始化(如SDK、全局配置)
}

export class MySubModule {
  // 可选:也可以在模块构造函数中自动执行初始化
  constructor(private store: Store, private router: Router) {
    initMfeDependencies(store, router);
  }
}

Shell侧修改加载逻辑

// Shell/src/app/routes.ts
import { inject } from '@angular/core';
import { Store } from '@ngrx/store';
import { Router } from '@angular/router';
import { loadRemoteModule } from '@angular-architects/module-federation';

const routes = [
  {
    path: 'todo',
    loadChildren: () =>
      loadRemoteModule({
        type: 'module',
        remoteEntry: 'http://localhost:4300/remoteEntry.js',
        exposedModule: './MySubModule',
      }).then((m) => {
        // 手动触发MFE初始化(如果MFE没有在构造函数自动执行)
        const shellStore = inject(Store);
        const shellRouter = inject(Router);
        m.initMfeDependencies?.(shellStore, shellRouter);
        return m.MySubModule;
      }),
  },
];

2. 用APP_INITIALIZER提前加载MFE配置

如果MFE的配置需要在模块加载前就就绪,可以在Shell的根模块中使用APP_INITIALIZER提前拉取MFE的配置文件,存入全局上下文后再加载MFE模块。

Shell侧预加载配置

// Shell/src/app/app.module.ts
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { HttpClient } from '@angular/common/http';

// 预加载MFE配置
function loadMfeConfig(http: HttpClient) {
  return () => 
    http.get('http://localhost:4300/mfe-config.json')
      .toPromise()
      .then(config => {
        // 将配置存入全局对象,供MFE读取
        if (!window['mfeConfigs']) window['mfeConfigs'] = {};
        window['mfeConfigs']['mySubModule'] = config;
      })
      .catch(err => console.error('MFE配置加载失败:', err));
}

@NgModule({
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: loadMfeConfig,
      deps: [HttpClient],
      multi: true
    }
  ]
})
export class AppModule {}

MFE侧读取配置初始化

// MFE/src/app/my-sub/my-sub.module.ts
export class MySubModule {
  constructor(private store: Store, private router: Router) {
    const mfeConfig = window['mfeConfigs']?.['mySubModule'];
    if (mfeConfig) {
      // 根据配置注册NgRx Feature
      registerTodoFeature(store, mfeConfig.storeConfig);
      // 根据配置添加路由
      router.config.unshift(...mfeConfig.routes);
    }
  }
}

3. 拆分初始化模块与业务模块

通过Module Federation将MFE的初始化逻辑单独暴露为一个模块,Shell先加载并执行初始化,再加载业务模块,确保配置先于业务代码就绪。

MFE侧配置暴露模块

// MFE/module-federation.config.js
module.exports = {
  name: 'mySubMfe',
  exposes: {
    './MySubModule': './src/app/my-sub/my-sub.module.ts',
    './MfeInit': './src/app/mfe-init.ts' // 单独暴露初始化模块
  },
  shared: {
    '@angular/core': { singleton: true, strictVersion: true },
    '@ngrx/store': { singleton: true, strictVersion: true },
    '@angular/router': { singleton: true, strictVersion: true }
  }
};

Shell侧顺序加载模块

// Shell/src/app/routes.ts
import { inject } from '@angular/core';
import { Store } from '@ngrx/store';
import { Router } from '@angular/router';
import { loadRemoteModule } from '@angular-architects/module-federation';

const routes = [
  {
    path: 'todo',
    loadChildren: () =>
      Promise.all([
        // 先加载初始化模块
        loadRemoteModule({
          type: 'module',
          remoteEntry: 'http://localhost:4300/remoteEntry.js',
          exposedModule: './MfeInit',
        }),
        // 再加载业务模块
        loadRemoteModule({
          type: 'module',
          remoteEntry: 'http://localhost:4300/remoteEntry.js',
          exposedModule: './MySubModule',
        })
      ]).then(([initModule, mfeModule]) => {
        const shellStore = inject(Store);
        const shellRouter = inject(Router);
        // 执行初始化
        initModule.init(shellStore, shellRouter);
        return mfeModule.MySubModule;
      }),
  },
];

注意事项

  • 确保Shell与MFE的共享依赖(如NgRx、Router)版本一致,启用singleton: true避免多实例冲突
  • 所有初始化逻辑需添加容错处理,避免配置加载失败导致整个MFE无法使用
  • 尽量减少MFE对Shell全局变量的依赖,优先通过函数参数传递必要依赖

内容的提问来源于stack exchange,提问作者Gnik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 09:20:19