Using shared settings between multiple environments in Angular πŸš€

nikosanif

Nikos Anifantis

Posted on April 2, 2021

Using shared settings between multiple environments in Angular πŸš€

The problem πŸ˜•

When we create a new Angular project, by default Angular CLI creates two environment files for development and production.

But in real world software development workflow, we may need more custom environments (e.g. staging, qa). Moreover, there are some environmental variables that are common between these environments. For example, API URL to fetch data from server. Thus, we must find a way to share the base settings across all environments and override them as needed.

In this article, we are going to learn:

  • How to add custom environments (e.g. staging)
  • How we can share some common settings between environments

Create a custom environment πŸ’Ž

Open your Angular project and create a new file under environments folder. In this example, we create a new environment for staging (environment.staging.ts file).

πŸ”– TIP: The name of the file should follow the naming convention:

environment.<your-env-name>.ts

Create new staging env file

Great, let's add some configuration in our new env file...



// environment.staging.ts

export const environment = {
  production: true,
  environmentName: "staging",
  apiUrl: "<your-api-url-here>",
};


Enter fullscreen mode Exit fullscreen mode

Update angular.json config file πŸ‘ˆ

Once you have created the new environment file, you have to specify file replacements for different environments. In your angular.json file find the following paths:

  • projects.<your-project-name>.architect.build.configurations
  • projects.<your-project-name>.architect.serve.configurations

Update the sections as the following example:



// angular.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "<your-project-name>": {
      // ...

      "architect": {
        "build": {
          //...
          "configurations": {
            //...
            "staging": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.staging.ts"
                }
              ]
            }
          }
        },
        "serve": {
          //...
          "configurations": {
            "staging": {
              "browserTarget": "<your-project-name>:build:staging"
            }
          }
        }
      }
    }
  }
}


Enter fullscreen mode Exit fullscreen mode

The problem is still out there πŸ’₯

Although we have created a new custom environment, in a typical project setup we may have duplication of environmental settings in which the values may be shared between them.

An example is depicted below where the API URL is common for all environments:



// environment.ts

export const environment = {
  production: false,
  environmentName: "development",
  apiUrl: "https://my-api.com/api", // common setting
};


Enter fullscreen mode Exit fullscreen mode


// environment.prod.ts

export const environment = {
  production: true,
  environmentName: "production",
  apiUrl: "https://my-api.com/api", // common setting
};


Enter fullscreen mode Exit fullscreen mode


// environment.staging.ts

export const environment = {
  production: true,
  environmentName: "staging",
  apiUrl: "https://my-api.com/api", // common setting
};


Enter fullscreen mode Exit fullscreen mode

In this example, the common settings is not a real problem, since there is only one shared value between the existing environments.

But... Imagine a real world Angular project which has at least 4-5 environments and a bunch of settings that developers have to maintain. This is really a problem, believe me... 😟πŸ˜₯

Create a common environment πŸ’¦πŸ”₯

Let’s make our life easy by using a base configuration file for common settings across all environments.

First, in your project create a new file with name environment.common.ts under the environments folder.

Create new staging env file

The next step is to add all base configuration in there...



// environment.common.ts

export const commonEnv = {
  production: false,
  environmentName: "development",
  apiUrl: "https://my-api.com/api",
};


Enter fullscreen mode Exit fullscreen mode

Last step is to change the existing environment files by importing the common file and override only the necessary settings.

In this example we don't need to override anything for the default environment (development).



// environment.ts

import { commonEnv } from "./environment.common";

const env: Partial<typeof commonEnv> = {};

// Export all settings of common replaced by dev options
export const environment = Object.assign(commonEnv, env);


Enter fullscreen mode Exit fullscreen mode

But, for production and staging we have to override some settings from the base.



// environment.prod.ts

import { commonEnv } from "./environment.common";

const env: Partial<typeof commonEnv> = {
  production: true,
  environmentName: "production",
};

// Export all settings of common replaced by dev options
export const environment = Object.assign(commonEnv, env);


Enter fullscreen mode Exit fullscreen mode


// environment.staging.ts

import { commonEnv } from "./environment.common";

const env: Partial<typeof commonEnv> = {
  production: true,
  environmentName: "staging",
};

// Export all settings of common replaced by dev options
export const environment = Object.assign(commonEnv, env);


Enter fullscreen mode Exit fullscreen mode

We use the Object.assign() method that allows you to copy all enumerable own properties from one or more source objects to a target object, and return the target object.

πŸ”– Pro Tip

Instead of Object.assign() method, you can use the spread operator.



export const environment = { ...commonEnv, ...env };


As an alternative, if you have more advanced setting with nested properties, I recommend to use merge function from lodash library.



export const environment = _.merge(commonEnv, env);


There is one more extremely useful trick here to preserve typings with typescript.
We use Partial<typeof commonEnv> in order to help us to track the properties of the common environment and override them correctly.

Use environment settings inside project ✨

Great! We have created multiple environments and now is time to use them in our project.

You can import environment settings in your services/components like the following example:



import { Component } from "@angular/core";
import { environment } from "src/environments/environment"; // here is the import

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class AppComponent {
  private apiUrl: string;

  constructor() {
    this.apiUrl = environment.apiUrl;
    // ...
  }
}


Enter fullscreen mode Exit fullscreen mode

Please be careful! Don't import your settings from the direct environment file!

For example:



// DO NOT
import { environment } from "src/environments/environment.staging";

// DO
import { environment } from "src/environments/environment";


Enter fullscreen mode Exit fullscreen mode

❗ Attention

We saw how to import environment settings in our project...
But it's NOT good idea to import them directly at your components or services.

I suggest to create a new Angular service (e.g. ConfigService) and handle all settings from there by injecting it in your components.
Thus, you will have a cleaner and more maintainable code.

Run/Build your project πŸ“¦

We are reaching the end, the hard work is done!
Now it's time to run and build your application for targeted environment by specific --configuration parameter with Angular CLI.

In order to build our application in staging mode, run one of the following commands:



# Builds and serves your app, rebuilding on file changes.
$ ng serve --configuration staging

Enter fullscreen mode Exit fullscreen mode


# Compiles an Angular app into an output directory
$ ng build --configuration staging

Enter fullscreen mode Exit fullscreen mode




Conclusion βœ…

Hooray! We’re done! πŸ‘

I hope you enjoyed this guide and will make your applications even more clean and maintainable by splitting environments to separate reusable configuration files! This approach can help in an excellent way in the enterprise organization setting!

Please support this article with your ❀️ πŸ¦„πŸ”– to help it spread to a wider audience πŸ™.

πŸ’– πŸ’ͺ πŸ™… 🚩
nikosanif
Nikos Anifantis

Posted on April 2, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related