Angular 5 и lerna NullInjectorError: Нет поставщика для InjectionToken
Мой вариант использования следующий:
- У меня есть 2 библиотеки angular5.
- Обе библиотеки клонированы из следующего проекта: https://github.com/robisim74/angular-library-starter
- У меня есть монорепо, которым управляет Лерна
- дочерняя библиотека имеет очень простую директиву, которую должна использовать родительская библиотека.
код для детской библиотеки
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]: NullInjectorError: Нет поставщика для идентификатора платформы InjectionToken! Ошибка: StaticInjectorError[ID платформы InjectionToken]: в _NullInjector.get (веб-пакет:///node_modules/@angular/core/esm5/core.js:923:0 <- spec.bundle.js: 3517: 19) в resolToken (webpack: ///node_modules/@angular/core/esm5/core.js: 1211: 0 <- spec.bundle.js: 3805: 24) в tryResolveToken (webpack: /// node_modules / @ angular / core / esm5 / core.js: 1153: 0 <- spec.bundle.js: 3747: 16) в StaticInjector.get (веб-пакет: ///node_modules/@angular/core/esm5/core.js: 1024: 0 <- spec.bundle.js: 3618: 20) в resolToken (веб-пакет: ///node_modules/@angular/core/esm5/core.js: 1211: 0 <- spec.bundle.js: 3805: 24) в tryResolveToken (веб-пакет: // /node_modules/@angular/core/esm5/core.js:1153:0 <- spec.bundle.js: 3747: 16) в StaticInjector.get (веб-пакет: /// node_modules / @ angular / core / core / esm5 / core. js: 1024: 0 <- spec.bundle.js: 3618: 20) at resolNgModuleDep (веб-пакет: ///node_modules/@angular/core/esm5/core.js: 10584: 0 <- spec.bundle.js: 13178: 25) в NgModuleRef_.get (веб-пакет: ///node_modules/@angular/core/esm5/core.js: 11805: 0 <- spec.bundle.js: 14399: 16) at resolDep (веб-пакет: ///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'}
Ошибка все еще там.
пакеты как символические ссылки
У меня есть новая теория, почему это происходит с моей стороны. Я думаю, так как я использую lerna для управления своими пакетами и зависимостями пакетов. И так как я добавил дочерний модуль в модуль хоста через lerna, то lerna создает символическую ссылку дочернего модуля в модулях узла хоста. Итак, моя теория состоит в том, что DI не может определить, что ему нужно вводить, когда библиотека, которую мы используем, является символической ссылкой. Попытка выяснить, как запустить тесты с помощью --preserve-symlinks
большое спасибо
2 ответа
Таким образом, проблема была действительно символическими ссылками. при использовании символических ссылок в ваших node_modules или использовании инструмента управления пакетами, такого как lerna (который связывает внутренние пакеты с помощью symlink). Чем Angular не будет знать, как правильно вводить предметы.
Для меня решение было до запуска тестов, чтобы удалить символические ссылки, установить пакеты с бумажной копией и затем запустить тесты.
Я столкнулся с той же проблемой в мультимодульном проекте Angular 6 и в Lerna.
Во-первых, есть опция под названием preserveSymLinks
установить в true
в угловом конфигурационном файле (angular.json
в угловых 6).
После этого я смог связать модуль со своим проектом со ссылкой на символику, но не со ссылкой на Лерну. Я не знаю почему, но я должен сделать это с помощью команды mklink в среде Windows.