Angular 5 和 lerna NullInjectorError : No provider for InjectionToken

标签 angular dependency-injection angular2-injection lerna

我的用例如下:

子库代码

import { NgModule } from '@angular/core';
import {CommonModule} from "@angular/common";

@NgModule({
    imports: [CommonModule],
    declarations: [
        SampleDirective
    ],
    exports: [
        SampleDirective
    ]
})
export class ChildModule { }

子库中指令的代码

import {Directive, PLATFORM_ID, Inject} from '@angular/core';

@Directive({
    selector: '.sample'
})
export class SampleDirective {
    constructor(@Inject(PLATFORM_ID) private _element: Object) {

    }
}

在父模块中我安装了子模块并且我正在做下面的简单单元测试

import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {Component} from '@angular/core';
import {ChildModule} from "@nz/child-lib";

@Component({
    selector: 'nz-host',
    template: `
        <div class="sample"></div>
    `
})
export class TestWrapperComponent{}


describe('injection problem', () => {
    let testFixture: ComponentFixture<TestWrapperComponent>;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [TestWrapperComponent],
            imports: [ChildModule]                
        });
    }));

    beforeEach(async(() => {
        testFixture = TestBed.createComponent(TestWrapperComponent);
        testFixture.detectChanges();
    }));

    it('test', () => {
        expect(true).toBe(true);
    });
});

当我运行测试时,出现以下错误:

StaticInjectorError[InjectionToken Platform ID]: NullInjectorError: No provider for InjectionToken Platform ID! Error: StaticInjectorError[InjectionToken Platform ID]: at _NullInjector.get (webpack:///node_modules/@angular/core/esm5/core.js:923:0 <- spec.bundle.js:3517:19) at resolveToken (webpack:///node_modules/@angular/core/esm5/core.js:1211:0 <- spec.bundle.js:3805:24) at tryResolveToken (webpack:///node_modules/@angular/core/esm5/core.js:1153:0 <- spec.bundle.js:3747:16) at StaticInjector.get (webpack:///node_modules/@angular/core/esm5/core.js:1024:0 <- spec.bundle.js:3618:20) at resolveToken (webpack:///node_modules/@angular/core/esm5/core.js:1211:0 <- spec.bundle.js:3805:24) at tryResolveToken (webpack:///node_modules/@angular/core/esm5/core.js:1153:0 <- spec.bundle.js:3747:16) at StaticInjector.get (webpack:///node_modules/@angular/core/esm5/core.js:1024:0 <- spec.bundle.js:3618:20) at resolveNgModuleDep (webpack:///node_modules/@angular/core/esm5/core.js:10584:0 <- spec.bundle.js:13178:25) at NgModuleRef_.get (webpack:///node_modules/@angular/core/esm5/core.js:11805:0 <- spec.bundle.js:14399:16) at resolveDep (webpack:///node_modules/@angular/core/esm5/core.js:12301:0 <- spec.bundle.js:14895:45)

我的 package.json 是这样的:

"dependencies": {
    "tslib": "^1.7.1"
},
"peerDependencies": {
    "@angular/common": ">= 5.0.0",
    "@angular/core": ">= 5.0.0"
},
"devDependencies": {
    "@angular/animations": "5.0.0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/compiler-cli": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/platform-server": "5.0.0",
    "@compodoc/compodoc": "1.0.3",
    "@nz/child-lib": "^0.0.1",
    "@types/jasmine": "2.6.2",
    "@types/node": "8.0.47",
    "chalk": "2.3.0",
    "codelyzer": "4.0.2",
    "core-js": "2.5.1",
    "istanbul-instrumenter-loader": "3.0.0",
    "jasmine-core": "2.8.0",
    "karma": "1.7.1",
    "karma-chrome-launcher": "2.2.0",
    "karma-coverage-istanbul-reporter": "1.3.0",
    "karma-jasmine": "1.1.0",
    "karma-sourcemap-loader": "0.3.7",
    "karma-spec-reporter": "0.0.31",
    "karma-webpack": "2.0.5",
    "reflect-metadata": "0.1.10",
    "rollup": "0.50.0",
    "rollup-plugin-license": "0.5.0",
    "rollup-plugin-node-resolve": "3.0.0",
    "rollup-plugin-sourcemaps": "0.4.2",
    "rxjs": "5.5.2",
    "shelljs": "0.7.8",
    "source-map-loader": "0.2.3",
    "ts-loader": "3.1.1",
    "tslint": "5.8.0",
    "tslint-angular": "1.0.0",
    "typescript": "2.4.2",
    "uglify-js": "3.1.6",
    "webpack": "3.8.1",
    "zone.js": "0.8.18"
}

即使在使用以下代码模拟 PLATFORM_ID 时也是如此

{provide: PLATFORM_ID, useValue: 'browser'}

错误仍然存​​在。

作为符号链接(symbolic link)的包

我有一个新的理论,为什么它会发生在我这边。 我想因为我正在使用 lerna 来管理我的包和包依赖性。 并且由于我通过 lerna 将子模块添加到主机模块,然后 lerna 在主机的节点模块中创建子模块的符号链接(symbolic link)。 所以我的理论是,当我们使用的库是符号链接(symbolic link)时,DI 无法识别他需要注入(inject)什么。 试图找出如何使用 --preserve-symlinks 运行测试

非常感谢

最佳答案

所以问题确实是符号链接(symbolic link)。 在您的 node_modules 中使用符号链接(symbolic link)或使用像 lerna 这样的包管理工具(它使用符号链接(symbolic link)链接内部包)时。 比 Angular 不知道如何正确注入(inject)项目。

我的解决方案是在运行测试之前删除符号链接(symbolic link),使用硬拷贝安装包,然后运行测试。

关于Angular 5 和 lerna NullInjectorError : No provider for InjectionToken,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48639549/

相关文章:

javascript - 在 Angular 2 层次结构中将服务提供者放在哪里,以便组件可以使用相同的服务实例相互通信?

image - BASE64 到图像 Angular 2

javascript - 在使用依赖注入(inject)时,如何避免用类型检查逻辑填充我的 JavaScript 代码?

javascript - Angular 6 : Function call within HTML interpolation returns undefined

android - Roboblender 使用带有多个模块的注释数据库

unit-testing - 我可以在 Visual Studio 单元测试(类库)项目中使用 Xamarin.Forms.DependencyService 吗?

angular - 获取对 Angular 2.X 自定义模块中注入(inject)器的引用?

angularjs - 注入(inject)的服务在构造函数中未定义

angular - 使用 angularfire2 时要在 ngrx/store 中存储什么?

Angular 2 组件 : How to handle circular Inputs and Outputs