【问题标题】:Passing environment variables to angular library将环境变量传递给角度库
【发布时间】:2017-09-17 16:50:00
【问题描述】:

我使用 angualr2-library yeoman 生成器创建了公司内部库。

一些 Angular 服务在我们当前的应用程序中使用环境变量(每个 env 上的 api 端点都发生了变化)。我想知道将当前环境对象传递给 angular2 库服务的最佳方法是什么?

【问题讨论】:

  • 你得到这个答案了吗?我想做同样的事情

标签: angular angular-cli


【解决方案1】:

如果您仍在寻找解决方案,这就是我如何完成与您所要求的类似的事情(使用 Angular 4.2.4)。

在您的AppModule(或您要导入库的位置)中,调用LibraryModule 上的forRoot() 方法。借助此功能,您可以将任何配置值传递给您的库,例如您应用的环境。

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

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        ...
        LibraryModule.forRoot(environment)
    ],
    bootstrap: [AppComponent]
})
export class AppModule {
}

LibraryModule 当然需要提供forRoot() 方法。 然后在 providers 数组中你可以提供服务,值and more。在这种情况下,为简单起见,'env' 充当持有给定环境对象的令牌。您也可以改用InjectionToken

@NgModule({
    ...
})
export class LibraryModule {

    public static forRoot(environment: any): ModuleWithProviders {

        return {
            ngModule: LibraryModule,
            providers: [
                ImageService,
                {
                    provide: 'env', // you can also use InjectionToken
                    useValue: environment
                }
            ]
        };
    }
}

由于令牌env 现在由您的LibraryModule 提供,您可以将其注入其所有子服务或组件中。

@Injectable()
export class ImageService {

    constructor(private http: Http, @Inject('env') private env) {
    }

    load(): Observable<any> {
        // assume apiUrl exists in you app's environment:
        return this.http.get(`${this.env.apiUrl}/images`)
            .map(res => res.json());
    }

}

希望对你有帮助!

【讨论】:

  • 这是个好主意,但在我的情况下,我的 appModule 也使用环境变量,它取决于我的库是否更改了什么?但两者并不同步。有没有可以解决的
  • 如果我想更改environment 值并想在我的appModule 中显示更改的环境值怎么办?我可以这样做吗。因为当 LibraryModule 在应用模块之外更改环境值时,它不会反映在应用模块中@Günter Zöchbauer
  • @pschild 我完全按照您所说的做了,我在提供程序数组中获取了环境配置,但是当将其注入服务时,该值是未定义的。你知道为什么吗?
  • @bsh 很难说发生了什么。你能用stackblitz创建一个简单的演示来显示问题吗?你使用哪个版本的 Angular?
  • @pschild 那么您将如何在 !environment.production 等库中执行开发模块的条件加载? StoreDevtoolsModule.instrument() : []
【解决方案2】:

我在a GitHub issue 中找到了该问题的替代解决方案。 GitHub线程中的解决方案有一个错误(错字),所以我在这里包括了固定的解决方案:

首先,将提供程序添加到包含您的环境文件的顶级 AppModule。

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

@NgModule({
  providers: [
    {provide: 'environment', useValue: environment}
  ]
  // object properties omitted for brevity...
})
class AppModule {}

最后,使用 Inject 装饰器将您的环境文件包含在您希望的应用程序的任何其他部分(库或其他)中:

@Component({
  // object properties omitted for brevity
})
class MyComponent {

  private environment

  constructor(
    @Inject('environment')
    environment
  ) {
    this.environment = environment
  }

}

【讨论】:

  • 你成功了。不错的一个
  • 最佳解决方案 ?? 优雅而简单。
  • 这个解决方案对我来说是最好的,干净而且最小。谢谢!
【解决方案3】:

使用 Angular 11 的完整工作解决方案。假设您使用命令 ng generate library library1 生成了一个名为 library1 的库。

AppModule 文件

// Your other imports ...
import { Library1Module } from 'library1';
import { environment } from 'src/environments/environment';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,

    // Pass the data you want to share with your library. Here we will pass 'apiUrl'. 
    Library1Module.forRoot({ apiUrl: environment.apiUrl }),

    AppRoutingModule
  ]
})
export class AppModule { }

library1.module.ts('Library1' 模块主文件):

import { ModuleWithProviders, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Configurations } from './configurations';
import { Library1Component } from './library1.component';

@NgModule({
  declarations: [Library1Component],
  imports: [CommonModule],
  exports: [Library1Component]
})
export class Library1Module {

  // Create this static method in the library module.
  public static forRoot(config: Configurations): ModuleWithProviders<Library1Module> {

    return {
      ngModule: Library1Module,
      providers: [
        { provide: Configurations, useValue: config }
      ]
    };
  }

}

configurations.ts(在 'projects\library1\src\lib' 文件夹中声明这个类)。声明您需要从“环境”文件中获取的所有配置。

export class Configurations {
  public apiUrl: string;

  constructor() {
    this.apiUrl = '';
  }

}

library1.service.ts('Library1Service' 将接收配置对象)。

import { Injectable, Optional } from '@angular/core';
import { Configurations } from './configurations';

@Injectable({
  providedIn: 'root'
})
export class Library1Service {

  private _apiUrl = 'No value';

  constructor(@Optional() config?: Configurations) {
    if (config) {
      this._apiUrl = config.apiUrl;
    }
  }

  get apiUrl() {
    return this._apiUrl;
  }

}

library1.component.ts(使用配置数据的Library1 组件)。

import { Component } from '@angular/core';
import { Library1Service } from '../public-api';

@Component({
  selector: 'lib-library1',
  template: `
    <p>
      This component inside "library1" library and reads the values from "environment.ts" file.
    </p>

    <h1>API URL : {{apiUrl}}</h1>`
})
export class Library1Component {
  apiUrl = '';

  constructor(library1Service: Library1Service) {
    this.apiUrl = library1Service.apiUrl;
  }
}

app.component.ts(使用 library1 组件确认 URL 已传递到您的库)。

.......
<lib-library1></lib-library1>
.......

【讨论】:

    【解决方案4】:

    here我认为有更好的方法

    我认为你们会发现这很有用:使用抽象类作为可交换行为的依赖注入标记

    我在一个 Nx 项目中有 3 个 Angular 应用程序,它们共享一些常见的环境变量。公共站点、私人门户和管理应用程序。在我的库中,我使用了一个定义公共环境变量的抽象环境类。

    export abstract class Environment {
      abstract readonly production: boolean;
      abstract readonly appUrls: {
        readonly public: string;
        readonly portal: string;
        readonly admin: string;
      };
    }
    

    然后我将3个environment.ts文件改成如下。

    import { Environment } from '@my-lib-prefix/common';
    
    class EnvironmentImpl implements Environment {
      production = false;
      appUrls = {
        public: 'http://localhost:4200',
        portal: 'http://localhost:4201',
        admin: 'http://localhost:4202'
      };
    }
    

    export const environment = new EnvironmentImpl(); environment.prod.ts 当然与 dev environment.ts 是对称的。然后我在每个 Angular 应用程序的根 app.module.ts 中提供各自的环境依赖项。

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    
    import { AppComponent } from './app.component';
    import { Environment } from '@my-lib-prefix/common';
    import { environment } from '../environments/environment';
    
    @NgModule({
      declarations: [AppComponent],
      imports: [BrowserModule],
      providers: [{ provide: Environment, useValue: environment }],
      bootstrap: [AppComponent]
    })
    export class AppModule {}
    

    现在任何组件都可以以干净、通用的方式注入环境依赖项。

    import { Component } from '@angular/core';
    import { Environment } from '@my-lib-prefix/common';
    
    @Component({
      selector: 'my-login',
      templateUrl: './my-login.component.html'
    })
    export class MyLoginComponent {
      constructor(private env: Environment) {}
    }
    

    它强制每个 environment.ts 实现抽象类中定义的“通用”环境变量。此外,每个各自的 EnvironmentImpl 都可以使用特定于应用程序的特定环境变量进行扩展。这种方法看起来非常灵活和干净。干杯! ^_^

    【讨论】:

      【解决方案5】:

      如果您尝试为 firebase 传递环境变量,只需在您的库中使用它:

      @NgModule({
        declarations: [MyAngularComponent],
        exports: [MyAngularComponent],
        imports: [
          AngularFireModule,
          AngularFirestoreModule,
          CommonModule
        ]
      })
      export class MyAngularModule {
      
        public static forRoot(firebaseConfig: FirebaseOptions): ModuleWithProviders<MyAngularModule> {
      
          return {
            ngModule: MyAngularModule,
            providers: [
              { provide: FIREBASE_OPTIONS, useValue: firebaseConfig }
            ]
          }
        }
      }
      

      然后像 AngularFire 一样导入它...

      MyAngularModule.forRoot(environment.firebase)
      

      来自这个帖子:pass angularFire config imported in library using forRoot

      【讨论】:

        【解决方案6】:

        如果您仍在寻找答案。 在当前版本(即 Angular > 6)中,您无需执行任何操作。

        angular-cli 命令“ng build --prod(用于生产)& ng build(用于开发)”将为您处理。

        示例:如果您在开发环境中运行项目,则所有变量都从 src/environments/environment.ts 中捕获。 在您的组件库项目中,只需导入“import { environment } from 'environments/environment';” (请确保路径)将根据 angular-cli build 命令处理环境。

        【讨论】:

        • 这对我不起作用。当我尝试进行构建时,出现错误:“文件'/environment.ts'不在'rootDir'下
        • 我认为这仅在没有项目文件夹且只有 src 文件夹与您的代码时才有效。然后编译器会找到正确的环境文件。但是如果您在项目目录下使用环境/环境导入,它将不会从项目自己的环境文件中获取环境文件,而不是从 src 文件夹中获取环境文件。我通过使用 tsconfig 路径配置来解决这种情况,并将 @environment 路径添加到 'projects/MyProject/src/environment'
        猜你喜欢
        • 2019-09-05
        • 2013-12-29
        • 2021-09-05
        • 2020-03-27
        • 2017-03-30
        • 2018-08-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多