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

Angular 9 Monorepo中同一Injectable出现多实例的原因排查

Angular 9 Monorepo: Why is My Service Not a Singleton?

这问题我之前在monorepo项目里也踩过坑,核心原因是模块解析路径不一致,导致同一个服务被当成了两个不同的模块,最终生成了两个独立的类实例。下面给你拆解原因和解决方案:

问题根源

看你的tsconfig配置就能找到问题:

  • 应用里的@lib/*直接指向库的源码目录:../../../libs/mylib/src/lib/*
  • 库内部的@lib/*指向自己的src/lib/*

当Angular编译应用时,因为导入路径不同,TypeScript会把@lib/services/SomeService当成两个完全不同的模块(一个来自应用的路径,一个来自库的路径)。这就导致编译后生成了两份SomeService的类定义,自然注入的实例就不一样了。

解决方案

1. 统一模块路径,引用库的构建产物

在monorepo里,应用绝对不能直接引用库的源码,而是要引用库的构建输出。修改你的apps/myapp/tsconfig.app.json:

{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@app/*": ["app/*"],
      "@lib/*": ["../../../dist/libs/mylib/*"] // 指向构建后的库目录
    }
  }
}

这样应用和库内部的@lib/*导入都会指向同一个编译后的模块,TypeScript就会把它们当成同一个服务类。

2. 正确配置服务的提供者

你的SomeService只加了@Injectable()但没指定单例范围,需要明确配置:

import { Injectable } from '@angular/core';
@Injectable({
  providedIn: 'root' // 全局根注入器,确保全应用单例
})
export class SomeService { }

如果你的服务是库专属的,不想全局提供,也可以在库的NgModule里声明提供者:

// libs/mylib/src/lib/mylib.module.ts
import { NgModule } from '@angular/core';
import { SomeService } from './services/some.service';

@NgModule({
  providers: [SomeService]
})
export class MylibModule { }

然后在应用的AppModule里导入这个MylibModule,这样服务会被限定在该模块的注入器里,也是单例。

3. 清理缓存并重新构建

旧的编译缓存可能残留重复的类定义,先清理再构建:

ng clean
ng build mylib
ng serve myapp

验证

做完上面的步骤后,再调用someMethod,控制台就不会输出“Services are different”了,AppService.libSvc和直接注入的libSvc会是同一个实例,变量值也会同步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 09:02:48