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
相关产品推荐
相关产品推荐

