0

我已将 AngularFire 添加到我的项目中。在其自述文件中,我被指示AngularFireModule.initializeApp(...)AppModule

然而,在示例中,人们使用环境常量,这不是一个选项,因为部署要求有一个配置文件,然后在部署时根据部署到的环境替换变量。

我相信我的配置是在导入之后加载的,这意味着没有任何东西传递给.initializeApp(...)

app.module.ts

import { AngularFireModule } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';
...

export function initializeApp(appConfig: AppConfig) {
  return () => appConfig.load();
}

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    ...,
    AngularFireModule.initializeApp(AppConfig.firebase),
    AngularFireAuthModule
  ],
  providers: [
    AppConfig,
    { provide: APP_INITIALIZER, useFactory: initializeApp, deps: [AppConfig], multi: true },
    ...,
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

应用配置.ts

import { Injectable } from '@angular/core';
import { AppConfigModel } from './shared/models/app-config.model';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';

/**
 * This config pattern based off https://devblogs.microsoft.com/premier-developer/angular-how-to-editable-config-files/
 * which is referenced in Octopus Deploy blog here https://octopus.com/blog/javascript-configuration
 */
@Injectable()
export class AppConfig extends AppConfigModel {

  constructor(private http: HttpClient) {
    super();
  }

  /**
   * Loads the required config file from assets, depending on configName of environment.
   * This allows replacement of variables by Octopus Deploy
   */
  public load() {
    const jsonFile = `assets/config/config.${environment.configName}.json`;

    return new Promise<void>((resolve, reject) => {
      this.http.get(jsonFile).toPromise().then((response: AppConfigModel) => {
        this.mapConfigToProperties(response);
        resolve();
      }).catch((response: any) => {
        console.error('On config load', response);
        reject(`Could not config load file '${jsonFile}': ${JSON.stringify(response)}`);
      });
    });
  }

  private mapConfigToProperties(config: any) {
    Object.keys(config).forEach(key => {
      AppConfig[key] = config[key];
    });
  }
}

我非常想解决这个问题,而无需更改任何构建过程,并且只需能够使用AppConfig来检索配置。

包.json

{
  ...,
  "dependencies": {
    "@angular/animations": "^6.1.10",
    "@angular/cdk": "^6.3.0",
    "@angular/common": "^6.0.3",
    "@angular/compiler": "^6.0.3",
    "@angular/core": "^6.0.3",
    "@angular/fire": "^5.3.0",
    "@angular/forms": "^6.0.3",
    "@angular/http": "^6.0.3",
    "@angular/platform-browser": "^6.0.3",
    "@angular/platform-browser-dynamic": "^6.0.3",
    "@angular/router": "^6.0.3",
    "core-js": "^2.5.4",
    "firebase": "^7.7.0",
    "moment": "^2.24.0",
    "ng-pick-datetime": "^6.0.16",
    "ng-pick-datetime-moment": "1.0.7",
    "ngx-image-cropper": "^2.0.2",
    "ngx-smart-modal": "^7.1.1",
    "ngx-textarea-autosize": "^2.0.3",
    "ngx-toastr": "^10.0.4",
    "rxjs": "6.3.3",
    "zone.js": "^0.8.26"
  },
  ...
}

main.ts

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { FirebaseOptionsToken, AngularFireModule } from '@angular/fire';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.log(err));

4

1 回答 1

0

这可以通过向 提供参数来实现,platformBrowserDynamic(...)其中接受一个提供程序数组,类似于 的providers属性中的数组@NgModule

我们将通过使用这个参数来解决这个问题。我们将输入 firebase 配置的参数,然后将其从 AppModule 的导入中删除。

main.ts

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { FirebaseOptionsToken, AngularFireModule } from '@angular/fire';

if (environment.production) {
  enableProdMode();
}

// Get the config file
fetch(`assets/config/config.${environment.configName}.json`)
  .then(response => response.json())
  .then((response: any) => {
    // Here we add the additional provider
    platformBrowserDynamic([{provide: FirebaseOptionsToken, useValue: response.firebaseSettings}])
      .bootstrapModule(AppModule)
      .catch(err => console.log(err));
}).catch((response: any) => {
  console.error('On config load', response);
});

app.module.ts

import { AngularFireModule, FirebaseOptionsToken } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';
...

export function initializeApp(appConfig: AppConfig) {
  return () => appConfig.load();
}

// initialize app with empty config
const angularFireImport = AngularFireModule.initializeApp({});

// remove the provider that we have provided for in the platforBrowserDynamic
angularFireImport.providers = angularFireImport.providers.filter(
  (provider: any) => provider.provide !== FirebaseOptionsToken
);


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    ...,
    // import the module we constructed above without the provider
    angularFireImport,
    AngularFireAuthModule
  ],
  providers: [
    ...,
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

这个答案的灵感来自AngularFire2 App Init in Module Conflicts with Dynamic Config Data

关于提供者和角度依赖注入的附加阅读,链接

于 2020-01-21T21:56:18.550 回答