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

标签 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

进一步调查,问题似乎是依赖注入(inject)引起的。请参阅下面的示例。

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

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 不知道要向你的库类注入(inject)什么,因为 Dep1Dep2 在使用 useFactory 之前没有被注入(inject)。所以你可以简单地将失败示例中的 useFactory 更改为 useValue ,那么它一定没问题。

如果要为库实例使用工厂,则必须在库之前将Dep1Dep2 注入(inject)提供程序。如果 Dep1Dep2 本身没有任何依赖关系,那么它一定可以工作。如果它们也有依赖关系,你也必须注入(inject)它们。

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 装饰器分支您的库,以实现 Angular DI 兼容性。 IMO 简单、可维护且有用的选择。

关于angular - 在 Angular 的 DI 中使用从库导入的工厂函数时 AOT 编译失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51593884/

相关文章:

angular - 无法直接访问 FormControl 实例。无法读取未定义的属性 'invalid'

angular - 添加 span 元素以显示错误消息

Angular:事件和 "subscribe is not a function"错误

angular - 如何在 Angular 4 cli 项目中导入 ionicons (sass)

angular - 如何减小产品包大小?

angular-cli - 设置 Angular CLI 生成默认值

Angular Material 形成背景颜色

angular - 使用Docker构建Angular失败:nginx.conf-没有这样的文件

javascript - 在窗口函数 typescript 上访问类数据

html - Angular 4 Material - mat-button 样式未应用于 mat-dialog 组件