You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Angular 19 + Module Federation(ESM) + 独立组件场景下共享@angular/core为peerDependency时出现NG0200循环DI错误

Angular 19 + Module Federation(ESM) + 独立组件场景下共享@angular/core为peerDependency时出现NG0200循环DI错误

嗨,我之前做Angular 19微前端项目时,刚好踩过一模一样的坑!当时折腾了好一阵才摸透关键问题,咱们一步步来捋:

首先得搞明白,NG0200这个循环DI错误,本质上大多是**@angular/core没真正成为单例**——Host和Remote各自加载了一份@angular/core实例,导致DI容器冲突,进而触发循环依赖报错。

第一步:把Module Federation的共享配置严格对齐

不管是Host还是Remote的Webpack配置(或者Angular CLI生成的mf配置文件),@angular/core的共享规则必须完全一致,尤其是singletonstrictVersion这俩核心参数:

比如Host的shared配置要这么写:

shared: {
  '@angular/core': {
    singleton: true, // 强制单例,这是最关键的一步!
    strictVersion: true, // 版本不匹配直接报错,避免隐式兼容破坏单例
    requiredVersion: '^19.2.0', // 和你的项目版本严格对应
    includeSecondaries: true // 包含@angular/core的次级模块,防止漏共享
  },
  // 顺带把@angular/common、@angular/router这些核心依赖也按同样规则配置
  '@angular/common': {
    singleton: true,
    strictVersion: true,
    requiredVersion: '^19.2.0',
    includeSecondaries: true
  }
}

Remote的shared配置必须和Host完全同步!别觉得Remote用了peerDependency就可以随便写,只有两边配置对齐,Webpack才会确保Remote复用Host的@angular/core实例。

第二步:修正独立组件的导出与加载逻辑

因为用的是独立组件,Remote这边的导出要直接给组件本身,别套模块:

// Remote的暴露入口文件比如src/app/exposed.component.ts
import { MyStandaloneComponent } from './my-standalone.component';

export default MyStandaloneComponent;

Host这边加载时,别画蛇添足把组件加进模块的declarations里,直接用loadRemoteModule拿到组件就用:

// Host里的加载逻辑
import { loadRemoteModule } from '@angular-architects/module-federation';

async loadMyRemoteComponent() {
  const RemoteComponent = await loadRemoteModule({
    type: 'module', // 必须是module,适配ESM模式
    remoteEntry: 'http://localhost:4201/remoteEntry.js',
    exposedModule: './MyStandaloneComponent' // 和Remote的exposes配置对应
  }).then(m => m.default);
  
  // 用动态组件方式渲染,比如通过ViewContainerRef创建实例
  this.remoteComp = RemoteComponent;
}

第三步:把peerDependency的配置做扎实

Remote的package.json里,@angular/core必须老老实实呆在peerDependencies里,绝对不能出现在dependenciesdevDependencies里,不然Webpack会偷偷把它打包进去,直接破坏单例:

"peerDependencies": {
  "@angular/core": "^19.2.0",
  "@angular/common": "^19.2.0"
},
"dependencies": {
  // 这里绝对不能放@angular/core相关包!
}

打包完Remote后,可以去dist目录搜搜有没有@angular/core的代码,要是有就说明配置错了,得回头调整。

第四步:排查循环DI的具体业务场景

如果上面几步都做了还报错,大概率是组件或服务的注入逻辑有问题。比如Remote组件注入了Host的某个服务,而Host的服务又间接依赖了Remote的内容?这时候可以试试:

  • @Optional()修饰注入的依赖,避免强制注入导致循环
  • 或者用Injector手动获取依赖,别在构造函数里直接声明
  • 检查独立组件的providers数组,有没有不小心重复提供了Host已有的服务

最后:清缓存!重启服务!

别笑,Webpack的缓存有时候会搞鬼,把Host和Remote的dist目录全删了,再重新启动ng serve,确保是全新构建的环境。

备注:内容来源于stack exchange,提问作者Rajeev kotagiri

火山引擎 最新活动