Set-up Multiple Environments in Angular
Tags: angular, tutorial
Published: 2020-01-13 09:47:12

When I started developing with the Angular framework, I struggled quite a bit managing multiple environments configurations (prod and dev were my only friends). After some time I realized you could do much more with custom configs. I would like to share this short tutorial for Angular devs wannabees that have to setup multiple environments in their projects.

<!-- If you want to read more on the absolute necessity to develop using multiple environments for various phases of your projects, please read this excellent article: -->

##1) Most common environments

Before jumping straight into configuration, it might be useful to remind ourselves of some standard environment that could be useful to reproduce in your projects.

* Development

"The development environment (dev) is the environment in which changes to software are developed, most simply an individual developer's workstation" - *Wikipedia*.

The development environment is what you use when developing on your laptop. It is where all the garbade test data will be created by you, it is where things will break and will make your app filled with users called "qwe" or "aze". You absolutely want to separate your testing database from the rest especially since you might introduce braking changes in it.

* Testing

"The purpose of the test environment is to allow human testers to exercise new and changed code via either automated checks or non-automated techniques" - *Wikipedia*.

The testing environment is important in order to make sure that your changes/updates will not break other parts of the app being for example built by a team. It might be that other environmental factors affect your app that do not apply in your local dev environment and as such you should have a test environment at disposal.

* Staging 

"A stage or staging environment is an environment for testing that exactly resembles a production environment. It seeks to mirror an actual production environment as closely as possible and may connect to other production services and data, such as databases" - *Wikipedia*.

One of the most important environments in my opinion. The staging environment will replicate the production data and allow users to test features in near production conditions. You usually replicate production data by syncing databases every x period of time from prod to stage, not the reverse.

* Production

"The production environment is also known as live, particularly for servers, as it is the environment that users directly interact with".

You know it, the environment that your users will use. Where all the magic happens and the finished and polished products works perfectly (normally).

##2) Setup various environments on Angular

Now that you know everything on the basics of "multi-environments" development, it is time to understand how to implement it in Angular. In this tutorial, I will jump straight into an already existing repo initiate with `ng new`.

I am assuming your are using a terminal and a text editor combined during this tutorial.

####a) create several different environment files

From the source of your repo type (each line is a separate command):

```terminal
cd src/environments/
ls
```

Once you have typed this you will see printed all the files contained in your `environments` folder. If it's a new repo you should only see two files: `environment.ts` and `environment.prod.ts`. If you are already familiar with Angular you know that those files contain variables that can be used when using `ng serve`. The `environment.prod.ts` contains variables that will be used when using `ng serve --prod` while `environment.ts` variables will be used when using `ng serve` alone. This also works for `ng build` and `ng test`.

As you can see, Angular only has by default two environments supported: Production and Development. We would now like to implement Stage and Testing.

Type the following commands to create additional configuration files:

```
touch environment.testing.ts
touch environment.stage.ts
```

And fill them with variables and configs that should be used in each environment.

Great, we're done here... not quite!

##b) Change `angular.json`

You have created your config files, bravo!

Now type the following command:

```
cd ../..
ls
```

See this angular.json file? open it. This file is the used when using commands such as `ng serve` or `ng build` to configure certain tasks and act in a certain way.

Locate the following bits of text:

````JSON
"projectName": {
  ...
  "architect": {
    "build": {
      ...
      "configurations": {
        "production": {
          "fileReplacements": [
            {
              "replace": "src/environments/environment.ts",
              "with": "src/environments/environment.prod.ts"
            }
          ]
        }
      }
    ...
    }
    ...
  }
  ...
}
```

As you can see,there is a piece that instructs the production configuration to replace the standard `environment.ts` with `environment.prod.ts`. Your intuition is correct, replicate this for the other environments you want to setup. You might end up with something similar (please care about understanding all the other instructions, filerplacements is not the only thing available...):

```
"projectName": {
  ...
  "architect": {
    "build": {
      ...
      "configurations": {
        "production": {
          "fileReplacements": [
            {
              "replace": "src/environments/environment.ts",
              "with": "src/environments/environment.prod.ts"
            }
          ]
        },
        "stage": {
          "fileReplacements": [
            {
              "replace": "src/environments/environment.ts",
              "with": "src/environments/environment.stage.ts"
            }
          ]
        },
        "testing": {
          "fileReplacements": [
            {
              "replace": "src/environments/environment.ts",
              "with": "src/environments/environment.testing.ts"
            }
          ]
        }
      }
    ...
    }
    ...
  }
  ...
}
```

Replicate similar approach on the same file but a bit lower for the `"serve"` configurations:

```
"configurations": {
  "production": {
    "browserTarget": "projectName:build:production"
  },
  "stage": {
    "browserTarget": "projectName:build:stage"
  },
  "testing": {
    "browserTarget": "projectName:build:testing"
  }
}
```

and under the `"e2e"`:

```
"production": {
  "devServerTarget": "digimex-admin:serve:production"
},
"stage": {
  "devServerTarget": "digimex-admin:serve:stage"
},
"testing": {
  "devServerTarget": "digimex-admin:serve:testing"
}
```

You are now ready to use different environments from the same codebase!

####c) Go on, enjoy it!

To use different environment upon serving and building use the following commands:

```
ng serve
ng serve --configuration=testing
ng serve --configuration=stage
ng serve --prod
```

&&

```
ng build
ng build --configuration=testing
ng build --configuration=stage
ng build --prod
```

I for example use such configurations to connect to different Firebase projects that contain different users, data and functions.

Hope you enjoyed!