导入Angular库时APP_BOOTSTRAP_LISTENER注入令牌被重命名失效
问题
我用ng-packagr创建了名为NgxTest的测试库,该库使用APP_BOOTSTRAP_LISTENER注入令牌,代码如下:
import { APP_BOOTSTRAP_LISTENER, ComponentRef, NgModule } from "@angular/core"; @NgModule() export class NgxTest { static forRoot() { console.log(APP_BOOTSTRAP_LISTENER) return { ngModule: NgxTest, providers: [{ provide: APP_BOOTSTRAP_LISTENER, useFactory: async (c: ComponentRef<any>) => {}, multi: true, }] }; } }
将该库导入Angular项目时出现问题:我在app.config.ts中通过importProvidersFrom(NgxTest.forRoot())加载库配置:
import { ApplicationConfig, importProvidersFrom, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; import { NgxTest } from 'ngx-test'; export const appConfig: ApplicationConfig = { providers: [ provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), importProvidersFrom(NgxTest.forRoot()), ] };
以该方式导入时,APP_BOOTSTRAP_LISTENER注入令牌被从InjectionToken重命名为InjectionToken2,导致其在启动阶段无法执行,请问该如何解决?
解决方案
这个问题源于Angular独立模式与NgModule模式的令牌解析冲突,加上ng-packagr打包时可能产生的重复令牌实例问题,可通过以下方法解决:
1. 为库添加独立模式兼容的提供者函数
放弃在独立配置中使用importProvidersFrom加载NgModule的forRoot,改为在库中直接提供独立模式可用的提供者函数:
在NgxTest库中新增文件src/lib/providers.ts:
import { APP_BOOTSTRAP_LISTENER, ComponentRef } from "@angular/core"; export function provideNgxTest() { return [ { provide: APP_BOOTSTRAP_LISTENER, useFactory: async (c: ComponentRef<any>) => { // 此处编写你的启动监听逻辑 }, multi: true, } ]; }
在库的public-api.ts中导出该函数,然后在项目的app.config.ts中直接使用:
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; import { provideNgxTest } from 'ngx-test'; export const appConfig: ApplicationConfig = { providers: [ provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), ...provideNgxTest(), // 直接展开提供者数组 ] };
2. 确保Angular依赖版本完全一致
检查库和项目的package.json,将Angular核心依赖设为peerDependencies而非dependencies,避免重复引入:
库的package.json配置示例:
{ "peerDependencies": { "@angular/core": "^17.0.0" } }
这样能保证项目与库使用同一版本的Angular核心代码,避免出现多个InjectionToken实例。
3. 调整ng-packagr打包配置
在库的ng-package.json中添加配置,防止打包时嵌入Angular核心模块:
{ "$schema": "./node_modules/ng-packagr/ng-package.schema.json", "dest": "./dist/ngx-test", "lib": { "entryFile": "src/public-api.ts" }, "allowedNonPeerDependencies": [], "preserveSymlinks": true }
内容的提问来源于stack exchange,提问作者Usche
相关产品推荐
相关产品推荐

