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

时间:2018-07-30 12:21:40

标签: angular typescript angular-cli tsc

我有一个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();
  }

}

什么可能导致此问题?

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

1 个答案:

答案 0 :(得分:1)

Angular不知道要向您的Library类注入什么,因为在使用Dep1之前没有注入Dep2useFactory。因此,在失败的示例中,您只需将useFactory更改为useValue,就可以了。

OR

如果要对Library实例使用factory,则必须在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) {
  }

}

OR

您可以使用Injectible装饰器分支库,以实现角度DI兼容性。 IMO简单,可维护且有用的选择。