MrCroft
MrCroft

Reputation: 3089

Merge different config files in environment files

I'm trying to have separate config files which I import/merge in the environment files to provide a further global CONFIG object with all the right properties that are meant for the current environment.

config/production.ts:

export const APP_CONFIG = {
  api: {
    root: 'https://api.example.com'
  },
  cookie: {
    domain: '.example.com'
  },
  serviceWorker: {
    enabled: true
  }
  // ... many more more properties
};

config/local.ts:

export const APP_CONFIG = {
  // ... only properties that are different from production
  api: {
    root: 'http://api.example.local'
  },
  cookie: {
    domain: '.example.local'
  },
  serviceWorker: {
    enabled: false
  }
};

config/dev.ts:

export const APP_CONFIG = {
  // ... only properties that are different from production
  api: {
    root: 'http://localhost:8001'
  },
  cookie: {
    domain: 'localhost'
  }
};

And one more config file for a test environment.

Then, environment.prod.ts:

import { APP_CONFIG } from '../config/production';

export const environment = {
  production: true,
  CONFIG: APP_CONFIG
};

environment.ts:

import { APP_CONFIG as CONF_PROD } from '../config/production';
import { APP_CONFIG as CONF_DEV } from '../config/dev';

export const environment = {
  production: true,
  CONFIG: { ...CONF_PROD, ...CONF_DEV }
};

environment.local.ts:

import { APP_CONFIG as CONF_PROD } from '../config/production';
import { APP_CONFIG as CONF_LOCAL } from '../config/local';

export const environment = {
  production: true,
  CONFIG: { ...CONF_PROD, ...CONF_LOCAL }
};

Next, in my app.module.ts:

ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production && environment.CONFIG.serviceWorker.enabled })

So that the service worker is enabled only if both conditions are met: a) it is a production build (environment.production: true, not to be mistaken with the environment I build for) and b) I actually want the service worker enabled in that environment (CONFIG.serviceWorker.enabled).

Of course, in my .angular-cli.json I have them declared:

"environments": {
  "dev": "environments/environment.ts",
  "local": "environments/environment.local.ts",
  "test": "environments/environment.test.ts",
  "prod": "environments/environment.prod.ts"
}

If I ng build --prod --env=local I still get the ServiceWorker enabled in my app, although I set it to false in config/local.ts, which overrides the "serviceWorker" object in config/production.ts.

In fact, even if I set serviceWorker: { enabled: false } in ALL configs, no matter what environment I set with the --env flag when building, I always get the ServiceWorker enabled.

Also, if I check other environment.CONFIG properties at runtime (like environment.CONFIG.apiEndpoint or environment.CONFIG.cookieDomain), they are the ones that I would expect, based on the environment I specified with the --env flag when building. I don't know what am I missing here? If the CLI picks the right environment file on build time, based on the --env flag, why isn't the properly merged environment.CONFIG object also present at build time? If I move the serviceWorker config property directly in my environment files, it works. But the point is to have it with the rest of the config properties, in my config files which get merged in the environment files.

The point of this setup is that there might be a lot of config properties for the app, but only a few might differ from environment to environment. I don't want to write all of them in each environment file.

So, it makes sense to have the production config with all the properties, and then in a config for each of the other environments (dev/local, test) only have the properties that are different from production, so they can be merged, thus the current environment properties would be composed by the production config with some config properties overwritten by the config of the current environment.

Upvotes: 3

Views: 2552

Answers (1)

Seth Moore
Seth Moore

Reputation: 116

A solution is provided here, https://github.com/angular/angular-cli/issues/12190

environment.base.ts

export const environment = {
  production: false,
  foo: "bar"
}

environment.ts

import { environment as base } from "./environment.base";

export const environment = {
  ...base,
}

environment.prod.ts

import { environment as base } from "./environment.base";

export const environment = {
  ...base,
  production: true
}

Upvotes: 5

Related Questions