Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular 'apiUrl' in configurable json file #3536

Closed
olicooper opened this issue Apr 9, 2020 · 7 comments · Fixed by #3610
Closed

Angular 'apiUrl' in configurable json file #3536

olicooper opened this issue Apr 9, 2020 · 7 comments · Fixed by #3610

Comments

@olicooper
Copy link
Contributor

I'd like to deploy my angular application to different environments without having to edit the environment.prod.ts file and re-build for each environment. I have asked a similar question prior this (see #2669) but I wasn't able to get it working for my use case. I will try to explain below.

The main issue is that the ABP CoreModule makes an API call to get the 'application-configuration' (using the wrong api url) before I get chance to call SetEnvironment.

I need to be able to set the environment before the CoreModule uses the configuration but SetEnvironment needs to be called after the CoreModule is initialized otherwise the ngxs store isn't configured and the default environment.prod.ts would overwrite the one passed to SetEnvironment anyway.

As a test I wrote this code to run during application initialization:

import { Injectable, APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from 'environments/environment';
import { SetEnvironment, Config } from '@abp/ng.core';
import { Store } from '@ngxs/store';

@Injectable()
export class EnvironmentConfig {
  constructor(private injector: Injector) {}
  load() {
    const jsonFile = `/assets/env.json`;

    return new Promise<void>((resolve, reject) => {
      this.injector.get(HttpClient).get(jsonFile).toPromise()
        .then((response : Config.Environment) => {
          this.injector.get(Store)
            .dispatch(new SetEnvironment(<Config.Environment>{ ...environment, ...response }))
            .toPromise()
            .then(() => {
              console.debug("Environment configured");
              resolve();
            })
            .catch(() => reject("Unable to configure the environment"));
        })
        .catch((response: any) => {
            reject(`Could not load file '${jsonFile}': ${JSON.stringify(response)}`);
        })
    });
  }
}

export function initializeEnvironment(envConfig: EnvironmentConfig) {
  return () => envConfig.load();
}

@NgModule()
export class EnvironmentConfigModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: EnvironmentConfigModule,
      providers: [
      EnvironmentConfig,
      {
        provide: APP_INITIALIZER, 
        useFactory: initializeEnvironment, 
        deps: [EnvironmentConfig], 
        multi: true 
      }]
    }
  }
}

This was then used in the main AppModule:

@NgModule({

  // ....

  imports: [
    // ABP's 'CoreModule'
    CoreModule.forRoot({
      environment,
      requirements: {
        layouts: LAYOUTS,
      },
    }),

    // Added this...
    EnvironmentConfigModule.forRoot(),

    NgxsModule.forRoot(STORE_STATES, { developmentMode: !environment.production })
  ],

  // ....

})
export class AppModule { }
@mehmet-erim mehmet-erim self-assigned this Apr 10, 2020
@mehmet-erim mehmet-erim added this to the 2.6 milestone Apr 10, 2020
@mehmet-erim
Copy link
Contributor

I don't know can you change the api property before the app-configuration request. Because this is an APP_INITIALIZER factory. See https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/core.module.ts#L125

I'll research this problem. I want to ask a question. Why you don't run a node script that gets api data and update the environment files before the build?

@olicooper
Copy link
Contributor Author

Having a single build makes it much easier to deploy hundreds of times across environments or servers, or use docker containers or Traefik etc.
In our case, we are looking at having multiple instances of the application running to spread out the load. We also have development, staging, UAT and live environments that we'd like to build once and just change the configuration. This means we can be more confident in deploying to the live environments if we don't have to re-build each time.

Thanks for looking in to this!

@mehmet-erim
Copy link
Contributor

mehmet-erim commented Apr 14, 2020

I can add skipGetAppConfiguration property to forRoot options of CoreModule. Thus you can pass skipGetAppConfiguration: true and call GetAppConfiguration action manually where you wish.

@olicooper
Copy link
Contributor Author

olicooper commented Apr 16, 2020

Thanks for this. I have tried it and it seems to work as expected.

I'd still like to be able to call getInitialData once I have updated the config, @mehmet-erim is there something you could add to bypass skipGetAppConfiguration check within the function when I call it manually?

@mehmet-erim
Copy link
Contributor

@olicooper

You don't need to call getInitialData. You can call application-configuration API like below:

this.store.dispatch(GetAppConfiguration).subscribe(async () => {
        // below codes refresh the page sliently. That is required.
        const { shouldReuseRoute } = this.router.routeReuseStrategy;
        this.router.routeReuseStrategy.shouldReuseRoute = () => false;
        this.router.navigated = false;
        await this.router.navigateByUrl(this.router.url);
        this.router.routeReuseStrategy.shouldReuseRoute = shouldReuseRoute;
      });

@leonkosak
Copy link
Contributor

leonkosak commented Jul 30, 2020

@olicooper do you found solution how to have apiUrl in configuration file?

@olicooper
Copy link
Contributor Author

do you found solution how to have apiUrl in configuration file?

See: #4386 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants