简体   繁体   English

如何为 Angular 中的延迟加载模块加载远程配置文件

[英]How to load a remote config file for a lazy loaded module in Angular

I have an Angular (v6) SPA with a number of lazily loaded modules.我有一个 Angular (v6) SPA,其中包含许多延迟加载的模块。 At present I have a json file holding config for the app that can be changed via a separate admin interface, without requiring a rebuild/deploy of the app.目前,我有一个 json 文件,其中包含应用程序的配置,可以通过单独的管理界面进行更改,而无需重建/部署应用程序。 The config file is currently loaded in the APP_INITIALIZER, which works well to ensure I retrieve the config before allowing the app to fully bootstrap.配置文件当前加载在 APP_INITIALIZER 中,它可以很好地确保我在允许应用程序完全引导之前检索配置。

I want to split this config file up per module, having one general config loaded in the APP_INITIALIZER and only load the others when that particular module is lazy loaded.我想将此配置文件拆分为每个模块,在 APP_INITIALIZER 中加载一个通用配置,并且仅在该特定模块延迟加载时才加载其他配置。

Is there an accepted or best practice way to do this?是否有公认的或最佳实践方法来做到这一点? I can't seem to find anything in the angular docs or in general on the net.我似乎在 angular 文档或一般在网上找不到任何东西。 One approach may be to fetch the config in the modules constructor, but as far as I can see, there is no way for me to prevent the module continuing to load and setup all its components etc until after this config file is retrieved and stored somewhere.一种方法可能是在模块构造函数中获取配置,但据我所知,我无法阻止模块继续加载和设置其所有组件等,直到检索到此配置文件并将其存储在某处.

Could a route resolver serve this purpose perhaps, if I set it on the root route for the lazy loaded module?如果我将它设置在延迟加载模块的根路由上,路由解析器可能会达到这个目的吗? Eg Instead of returning any data, I could inject some "ConfigService" into the resolver, which will retrieve the appropriate config file and store it, and then let the resolver resolve.例如,我可以不返回任何数据,而是将一些“ConfigService”注入解析器,它会检索适当的配置文件并存储它,然后让解析器解析。

Then components in this module could inject this same ConfigService, getting access to whatever config points were retrieved.然后这个模块中的组件可以注入相同的 ConfigService,访问检索到的任何配置点。

Fetching the configuration during module initialization (either in the constructor or in a static method such as forRoot ) is not going to work, as dependencies have not been resolved at that point.在模块初始化期间获取配置(在构造函数中或在诸如forRoot之类的 static 方法中)将不起作用,因为此时尚未解决依赖关系。 So, for example, you won't have HttpClient available to fetch data.因此,例如,您将没有HttpClient可用于获取数据。

What could be a viable way:什么可能是可行的方法:

1. Provide a ConfigurationService that gets the URL of your config file injected 1. 提供一个ConfigurationService获取你的配置文件注入的 URL

@Injectable()
export class ConfigService {

  private config$ = new BehaviorSubject<any | null>(null);
  private loadedConfig = false;

  constructor(@Inject(CONFIG_URL) private configUrl: string,
              private httpClient: HttpClient) {
    this.getConfig();
  }

  getConfig(): Observable<any> {
    if (!this.loadedConfig) {
      this.loadedConfig = true;
      this.httpClient.get(this.configUrl).subscribe(this.config$);
    }
    return this.config$;
  }

}

2. Provide ConfigurationService as part of a module that can dynamically set CONFIG_URL : 2. 提供ConfigurationService作为可以动态设置CONFIG_URL的模块的一部分:

@NgModule({
  providers: [ConfigService],
  imports: [
    HttpClientModule
  ]
})
export class ConfigModule {
  static buildForConfigUrl(configUrl: string): ModuleWithProviders {
    return {
      ngModule: ConfigModule,
      providers: [
        {
          provide: CONFIG_URL,
          useValue: configUrl
        }
      ]
    };
  }
}

3. Import ConfigModule in your feature modules 3. 在您的功能模块中导入ConfigModule

Now when you have a feature module that is supposed to have its own configuration available, just import ConfigModule using buildForConfigUrl :现在,当您有一个应该有自己的配置可用的功能模块时,只需使用buildForConfigUrl ConfigModule

@NgModule({
  exports: [
    MyComponent
  ],
  declarations: [
    MyComponent
  ],
  imports: [
    ConfigModule.buildForConfigUrl('https://my-url/my-config.json')
  ]
})
export class FeatureModule {
}

4. Use ConfigService in your components: 4. 在您的组件中使用ConfigService

@Component({
  selector: 'my-component',
  template: 'I am your new component. My config is: {{ config$ | async | json }}'
})
export class MyComponent implements OnInit{

  config$: Observable<any>;

  constructor(private configService: ConfigService) {
  }

  ngOnInit(): void {
    this.config$ = this.configService.getConfig();
  }

}

With this approach, you nicely decoupled the concerns: Your feature modules don't need to care how the configuration is loaded, but still its components have the configuration available at runtime.使用这种方法,您可以很好地解耦关注点:您的功能模块不需要关心配置是如何加载的,但它的组件仍然具有在运行时可用的配置。

If you want to go one step further, you could even remove the definition of the config URLs from your feature modules and move it to your AppModule centrally.如果您想更进一步,您甚至可以从功能模块中删除配置 URL 的定义并将其集中移动到您的AppModule

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM