当从库导入的工厂函数在Angular中的DI中使用时,AOT编译失败



我有一个Angular 6.1应用程序,它导入一些外部模块。

当我在AOT模式下编译应用程序时:

$ ng build --aot

我得到这个错误:

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

路径node_modules/@acme/library/src/library/library指向一个library.d.ts文件,该文件位于模块目录中。

如果从外部包中完全删除键入信息,则应用程序将正确编译并工作。此外,如果我手动将所有的打字员合并到一个index.d.ts文件中,编译就可以很好地完成了。

我认为编译器解析类型定义文件的方式有问题,因为某种原因,它似乎没有寻找扩展名为.d.ts的文件。


更新1

外部模块@acme/library也是我开发和预编译的。它是一个简单的TypeScript库,带有一些导出的类和函数。它没有使用Angular的任何花哨的装饰器之类的东西。

它的package.json具有以下字段:

"es2015": "index.es2015.js",
"main": "index.min.js",
"module": "index.es5.js",
"typings": "index.d.ts",

所有提到的文件都存在于包的根目录中。


更新2

经过进一步调查,问题似乎是由依赖项注入引起的。请参阅下面的示例。

我正在使用一个自定义工厂提供程序,以便将Library的实例注入到组件的构造函数中。

libraryFactory函数是从外部模块导入的,它看起来像这样:

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) {
}
}

工作示例

然而,如果我去掉DI,它就会编译并正常工作:

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();
}
}

是什么原因导致了这个问题?

如果需要的话,我很乐意提供更多的具体信息。

Angular不知道要向Library类注入什么,因为以前使用useFactory时没有注入Dep1Dep2。因此,在失败的示例中,您可以简单地将useFactory更改为useValue,那么它一定是可以的。

如果要将工厂用于Library实例,则必须在Library之前将Dep1Dep2注入提供程序。如果Dep1Dep2本身没有依赖关系,那么它必须工作。如果它们也有依赖关系,您也必须注入它们。

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) {
}
}

您可以使用Injectible装饰器对库进行分支,以实现角度DI兼容性。IMO易于维护和有用的选择。

最新更新