切换远程应用时Module Federation的NGRX Effects无法正常工作
解决Module Federation下Angular远程应用NGRX Effects未注册问题
问题场景回顾
- Shell应用根模块配置了
StoreModule.forRoot({})和EffectsModule.forRoot({}) - 远程应用一:无NGRX状态,仅包含HTTP客户端
- 远程应用二:带NGRX状态,通过
APP_ROUTES暴露路由,路由指向内部懒加载特性,特性模块中配置StoreModule.forFeature(...)和EffectsModule.forFeature(...) - 异常表现:单独运行远程应用二正常;Shell中先打开远程应用二正常;先开远程一再切到远程二时,远程二的Effects未注册;刷新Shell/appTwo路由正常,从Shell/appOne切到Shell/appTwo时Effects失效
解决方案
1. 强制NGRX依赖单例共享
在Shell和所有远程应用的webpack Module Federation配置中,将@ngrx/store和@ngrx/effects设置为单例共享,避免多实例冲突:
// webpack.config.js(Shell及远程应用) module.exports = { plugins: [ new ModuleFederationPlugin({ // 其他配置 shared: { '@angular/core': { singleton: true, strictVersion: true }, '@ngrx/store': { singleton: true, strictVersion: true }, '@ngrx/effects': { singleton: true, strictVersion: true }, '@angular/common/http': { singleton: true, strictVersion: true } } }) ] };
2. 调整远程应用二的Effects注册方式
不要使用providedIn: 'root'声明Effects类,改为在特性模块的EffectsModule.forFeature中显式传入,并在providers数组中声明:
// 远程应用二的特性模块 import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; import { featureReducer } from './reducers'; import { FeatureEffects } from './effects'; @NgModule({ imports: [ StoreModule.forFeature('featureState', featureReducer), EffectsModule.forFeature([FeatureEffects]) // 显式注册特性Effects ], providers: [FeatureEffects] // 确保类被模块级注入 }) export class FeatureModule {}
3. 手动触发Effects注册
在远程应用二的路由模块(暴露APP_ROUTES的模块)的ngOnInit钩子中,手动注册Effects,确保模块加载时触发:
import { NgModule, OnInit } from '@angular/core'; import { RouterModule } from '@angular/router'; import { EffectsRunner } from '@ngrx/effects'; import { FeatureEffects } from './feature/effects'; @NgModule({ imports: [RouterModule.forChild(APP_ROUTES)], providers: [FeatureEffects] }) export class AppRoutesModule implements OnInit { constructor(private runner: EffectsRunner, private featureEffects: FeatureEffects) {} ngOnInit(): void { // 手动注册Effects this.runner.registerEffects(this.featureEffects); } }
4. 配置路由强制重新初始化
在Shell的路由配置中,给远程应用二的路由设置runGuardsAndResolvers: 'always',确保每次路由激活时都重新加载远程模块:
// Shell的路由配置 const routes: Routes = [ { path: 'appOne', loadChildren: () => import('appOne/AppModule').then(m => m.AppModule) }, { path: 'appTwo', loadChildren: () => import('appTwo/AppRoutesModule').then(m => m.AppRoutesModule), runGuardsAndResolvers: 'always' // 强制每次激活路由时重新处理 } ];
5. 修正根EffectsModule初始化
确保Shell的根模块中EffectsModule.forRoot传入空数组而非空对象:
// Shell的AppModule @NgModule({ imports: [ StoreModule.forRoot({}), EffectsModule.forRoot([]) // 这里传入空数组,而非空对象 ] }) export class AppModule {}
内容的提问来源于stack exchange,提问作者Ionut Mugurel Cinjau
相关产品推荐
相关产品推荐

