Angular 8 库使用@Optional @Host @Inject注入服务构建后返回null问题
Angular 8 自定义库构建后依赖注入返回null 排查方案
核心原因定位
该问题90%以上的场景是注入令牌的引用不匹配,直接引用源代码时所有模块的编译上下文一致,令牌是同一个实例;构建后的库和主项目处于不同编译上下文,如果令牌导出/引用方式错误,会导致注入器用两个不同的令牌实例匹配服务,自然返回null。
分步排查方案
第一步:校验注入令牌的导出和引用规则
Angular依赖注入完全依赖注入令牌的引用相等性,必须满足以下要求:
- 注入令牌必须在库的
public-api.ts(Angular库默认公共导出入口)中显式导出,不能只在内部文件定义 - 所有用到该令牌的位置(包括库内部、主项目)都必须通过库的包名导入,禁止直接引用库的内部相对路径
错误导入示例:
// 禁止!会导致编译后生成独立的令牌实例 import { MY_SERVICE_TOKEN } from '@my-lib/lib/tokens/my-service.token.ts'正确导入示例:
import { MY_SERVICE_TOKEN } from '@my-lib'- 注入令牌必须在库的
第二步:校验库的编译配置
- 确认库构建命令使用生产配置:执行
ng build <你的库名> --prod,开发模式构建的库会丢失部分元数据 - 检查库的
tsconfig.lib.json配置,确保以下字段为true:
{ "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true } }- Angular 8的Ivy预览版对自定义库的支持不完善,如果开启了Ivy,关闭库的Ivy编译,用ViewEngine构建后再测试。
- 确认库构建命令使用生产配置:执行
第三步:校验装饰器配置
- 临时移除
@Host装饰器测试注入是否正常,如果移除后可以拿到服务,说明服务提供的层级不在当前宿主的注入器范围内,需要调整父组件的服务提供位置,或者调整@Host的使用逻辑 - 确认服务提供时用的令牌和注入时用的是同一个,不要出现注入时用
MY_SERVICE_TOKEN,提供时直接用类的情况。
- 临时移除
第四步:调试验证令牌一致性
在库的注入位置、主项目的provide位置分别打印令牌:
console.log('令牌实例:', MY_SERVICE_TOKEN)如果构建后两个位置打印的引用不一致,就可以确认是令牌导出/引用的问题。
通用解决方案
如果排查后确认是令牌重复问题,可以给注入令牌添加唯一标识避免隐式重复:
// 库的令牌定义文件,第二个参数的字符串必须全局唯一 export const MY_SERVICE_TOKEN = new InjectionToken<MyService>('MY_UNIQUE_SERVICE_TOKEN_2024');
内容的提问来源于stack exchange,提问作者Dmitry Yanet
相关产品推荐
相关产品推荐

