I have an Angular 6.1 application, which imports some external module.
When I'm compiling the application in AOT mode:
$ ng build --aot
I'm getting this error:
ERROR in ./src/app.component.ngfactory.js
Module not found: Error: Can't resolve '/home/user/project/node_modules/@acme/library/src/library/library' in '/home/user/project/src/app'
resolve '/home/user/project/node_modules/@acme/library/src/library/library' in '/home/user/project/src/app'
using description file: /home/user/project/package.json (relative path: ./src/app)
Field 'browser' doesn't contain a valid alias configuration
using description file: /home/user/project/node_modules/@acme/library/package.json (relative path: ./src/library/library)
no extension
Field 'browser' doesn't contain a valid alias configuration
/home/user/project/node_modules/@acme/library/src/library/library doesn't exist
.ts
Field 'browser' doesn't contain a valid alias configuration
/home/user/project/node_modules/@acme/library/src/library/library.ts doesn't exist
.tsx
Field 'browser' doesn't contain a valid alias configuration
/home/user/project/node_modules/@acme/library/src/library/library.tsx doesn't exist
.mjs
Field 'browser' doesn't contain a valid alias configuration
/home/user/project/node_modules/@acme/library/src/library/library.mjs doesn't exist
.js
Field 'browser' doesn't contain a valid alias configuration
/home/user/project/node_modules/@acme/library/src/library/library.js doesn't exist
as directory
/home/user/project/node_modules/@acme/library/src/library/library doesn't exist
[/home/user/project/node_modules/@acme/library/src/library/library]
[/home/user/project/node_modules/@acme/library/src/library/library.ts]
[/home/user/project/node_modules/@acme/library/src/library/library.tsx]
[/home/user/project/node_modules/@acme/library/src/library/library.mjs]
[/home/user/project/node_modules/@acme/library/src/library/library.js]
@ ./src/app.component.ngfactory.js 12:0-92 30:102-122 30:186-206 33:204-224 33:289-309 36:204-224 36:289-309 45:102-122 45:187-207 51:102-122 51:187-207 120:102-122 120:187-207
@ ./src/app/app.module.ngfactory.js
@ ./src/main.ts
@ multi ./src/main.ts
The path node_modules/@acme/library/src/library/library
leads to a library.d.ts
file, which is present in module directory.
If I remove typing information altogether from the external package, the application compiles and works correctly. Also, if I manually merge all typings into a single index.d.ts
file, the compilation completes just fine.
I think there's something wrong in how the compiler resolves type definitions files, it appears like it's not looking for files with .d.ts
extension for some reason.
The external module @acme/library
, is also developed and pre-compiled by me. It's a simple TypeScript library with some exported classes and functions. It's not using anything fancy from Angular like decorators and stuff.
It's package.json
has the following fields:
"es2015": "index.es2015.js",
"main": "index.min.js",
"module": "index.es5.js",
"typings": "index.d.ts",
All mentioned files are present in the root directory of the package.
After further investigation, it looks like the problem is caused by the dependency injection. Please see the example below.
I'm using a custom factory provider in order to inject an instance of Library
to the constructor of the component.
The libraryFactory
function is imported from the external module and it looks like this:
export function libraryFactory(): Library {
const dep1 = new Dep1();
const dep2 = new Dep2();
return new Library(dep1, dep2);
}
import {Component} from '@angular/core';
import {Library, libraryFactory} from '@acme/library';
@Component({
selector: 'app-foo',
templateUrl: './foo.component.html',
providers: [
{
provide: Library,
useFactory: libraryFactory
}
]
})
export class FooComponent {
constructor(public library: Library) {
}
}
However, if I get rid of the DI it compiles and works correctly:
import {Component} from '@angular/core';
import {Library, libraryFactory} from '@acme/library';
@Component({
selector: 'app-foo',
templateUrl: './foo.component.html'
})
export class FooComponent {
public library: Library;
constructor() {
this.library = libraryFactory();
}
}
What could be causing this problem?
I will be glad to provide more specific information if needed on first request.
Angular does not know what to inject to your Library class because Dep1
and Dep2
is not injected before when using useFactory
. So you can simply change useFactory
to useValue
in your failing example, then it must be okay.
OR
If you want to use factory for Library instance, you have to inject Dep1
and Dep2
to providers before Library. If Dep1
and Dep2
have no dependencies themself it must work. If they have dependencies too, you have to inject them also.
import {Component} from '@angular/core';
import {Library, Dep1, Dep2} from '@acme/library';
const dep1instance = new Dep1();
const dep2instance = new Dep2();
@Component({
selector: 'app-foo',
templateUrl: './foo.component.html',
providers: [
{
provide: Dep1,
useValue: dep1instance
},
{
provide: Dep2,
useValue: dep2instance
},
{
provide: Library,
useFactory: (dep1: Dep1, dep2: Dep2) => new Library(dep1, dep2),
deps:[Dep1,Dep2]
}
]
})
export class FooComponent {
constructor(public library: Library) {
}
}
OR
You can just branch your library with Injectible
decorators for angular DI compatibility. IMO easy, maintainable and useful choice.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With