【问题标题】:Angular AOT Compilation Provide Config For LibraryAngular AOT 编译为库提供配置
【发布时间】:2017-08-25 05:31:18
【问题描述】:

不久前,我们开始创建包含 Angular 组件的内部 NPM 包,以便我们可以在不同站点之间重用我们常用的 Angular 组件。通过我们正在进行的一些新工作,我们正在尝试支持 AOT 编译以及使 NPM 包中的组件与 angular 2.x 和 4.x 兼容。我们有一些配置需要传递到 npm 包/库(api 键/url、环境等),所以我希望实现站点提供一个配置对象,可以将其注入需要这些值的组件中.我在让提供商与 AOT 合作时遇到问题。到目前为止,我能够让它工作的唯一方法是使用显式字符串标记,但这在我看来远非理想。

工作:

在消费 AOT 站点中:

import { environment } from './../environments/environment';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
  ],
  providers: [
      {
          provide: 'ConfigToken',
          useValue: environment
      }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

在库组件中:

constructor(@Inject('ConfigToken') private config: Configuration) { }

从库中导出的接口:

export interface Configuration {
    someValue: string;
    someOtherValue: string;
}

我试过了:

  • 从库中导出 OpaqueToken

  • 导出一个类以用作标记

    使用这两种策略,我最终都会遇到错误ERROR in Can't resolve all parameters for SomeComponent in C:/Development/path/to/bundle

【问题讨论】:

    标签: angular angular2-aot


    【解决方案1】:

    好吧,我最终找到了自己问题的答案……问题在于使用接口作为注入值的类型。我正在查看生成的 java 脚本并注意到这一点:

    SomeComponent.ctorParameters = function () { return [
        { type: undefined, decorators: [{ type: _angular_core.Inject, args: [MyProviderToken,] },] },
    ]; };
    

    一旦我将类型更改为类而不是接口,类型就不再是未定义的,并且 Angular 能够注入消费应用提供的值。

    【讨论】:

    • 很高兴知道,这是有道理的……注入器只能注入事物的实例,接口本身不能是实例。
    • 另一种可能性,是使用桶进行进口的问题。我一次做了太多的小改动。我有一种感觉,虽然它是两者的结合。但是,注入器应该传入 NgModule 声明中给出的对象,因为我使用的是useValue,而不是尝试创建它正在注入的数据类型的实例。但是,无论哪种方式,我确实学到了一些东西,这总是好的。有时仅查看编译代码是找到问题的最佳方法。 ¯_(ツ)_/¯
    【解决方案2】:

    您可以在可注入类上使用“useValue”选项在运行时重新定义它。这就是我为我的应用程序提供配置的方式。只需创建一个简单的可注入占位符,例如

     import { Injectable } from '@angular/core' 
    
     @Injectable() export class MyAppConfig {} 
    

    然后在您的模块中,您可以从任何文件中导入一些常量。假设 const 看起来像这样

     export const MY_APP_CONFIG = { 
         configOption1 = 'test1';
         configOption2 = 123;
     }
    

    现在在你的模块中,你可以导入可注入类和常量

     import { MyAppConfig } from './wherever/it/is'
     import { MY_APP_CONFIG } from './wherever/it/is'
    

    然后在提供者中

     providers: [
           {
              provide: MyAppConfig,
              useValue: MY_APP_CONFiG
           }
       ],
    

    据说有更好的方法来使用 InjectionToken https://angular.io/api/core/InjectionToken

    但这更简单,对我有用。据我了解,这种方法的缺点是它无法防止命名空间冲突。

    编辑 -

    至于如何在组件中消费...

    导入可注入的配置类

    import { MyAppConfig } from './wherever'
    

    然后在构造函数中

    constructor(private config: MyAppConfig) { 
         console.log(config);
    }
    

    您会看到它打印的是您分配给它的 const 的值,而不是一个空对象。

    【讨论】:

    • 我曾尝试导出一个类以用作提供令牌,但没有使用 @Injectable() 所以我试了一下添加它,但仍然遇到同样的错误。你在使用 AOT 编译吗?
    • 是的,我是,嗯。奇怪的。我读到您尝试过,但假设您的意思是您尝试过“useClass”。我的错。
    • 我不确定这是否重要,但在我的应用程序中,我基本上将整个应用程序作为一个单独的模块(一个导入一堆自己的子模块的模块),然后我导入该模块进入主 app.module.ts。我这样做是因为我希望能够获取我的应用程序并将其包含在其他应用程序中。但就目前而言,我的 app.module.ts 本质上是默认的样板 app.module.ts,而不是我的自定义应用程序模块的导入语句。然后在我的自定义应用程序模块中,我使用我向您描述的方法来提供运行时配置。希望这是有道理的......
    • 换句话说,我没有在运行时引导的 app.module.ts 中使用此方法来启动应用程序。但是它们基本上都是同时加载的,所以我不知道这有什么关系。
    • 我的 library/npm 包中有几个模块,它们声明/导出组件,这些组件被导入到 Angular CLI 项目中的主 AppModule 中。奇怪的是,如果我只使用字符串提供程序令牌,提供程序是否有效。此外,我还可以在我的 AppModule 中使用 { provide: SomeOtherService, useClass: SomeOtherService} 将服务注入到那些从非角度 npm 包中导入的组件中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-10
    • 1970-01-01
    • 2018-02-15
    • 2020-09-03
    • 2017-05-17
    • 2018-02-14
    • 2017-10-24
    相关资源
    最近更新 更多