Read System Environment Variables in Angular

A few weeks back I was working on a project where I needed to read system environment in Angular 7 from a Docker container before it builds. After days of searching, I came across a solution from multiple sources on the internet.

Keep one thing in mind, you will only be able to inject environment variables before your Angular app builds. Unlike Nodejs, you will not get real time access because you are running in an browser environment.

Custom Webpack

This method will involve creating a custom webpack which will use the dotenv package to get the variables.

Step 1: Install Dependencies for Custom Webpack

To read system environment variables in Angular you will first need to install the necessary dependencies that will allow you to to use a custom webpack.

npm i @angular-builders/custom-webpack @angular-builders/dev-server @angular-devkit/build-angular dotenv

Notice that we are installing a custom dev server and builder. Because of this, we will manually have to handle this in the Angular.json file.

Version Mismatch

I small gotcha, that I ran into was problems with version mismatch between build-angular and the custom webpack. Just for reference, using Angular 7 here are the versions of each that I have installed in my dependencies.

"@angular-builders/custom-webpack": "^7.2.0",
"@angular-builders/dev-server": "^7.2.1",
"@angular-devkit/build-angular": "^0.12.3",
"dotenv": "^6.2.0",

Step 2: Modify Angular.json

Now let’s modify the Angular.json file to use the custom-webpack on build and the dev-server when serving.

  "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "customWebpackConfig":{
              "path": "./extra-webpack.config.js"
            },
            "outputPath": "dist/",

Notice the property customWebpackConfig that will be the custom webpack file we will create. I’m putting it at the root but you can put it anywhere. Also, I am defining the outputPath on build.

Now let’s change the serve property:

 "serve": {
          "builder": "@angular-builders/dev-server:generic",
          "options": {
            "browserTarget": "track-and-trace:build"
          },

The only thing to change is the builder property.

Step 3: Webpack.config.js

Now create the ./extra-webpack.config.js specified earlier. Put the following in that file:

const webpack = require('webpack');

module.exports = {
    plugins: [new webpack.DefinePlugin({
        'process.env': {
            SERVER: JSON.stringify(process.env.SERVER),
            PEER: JSON.stringify(process.env.PEER)
        }
    })]
}

I am providing two variables to process.env. One is called server and the other is called *peer. Obviously, change these variables to whatever variables that you are looking for.

Step 4: Typings.d.ts

If you try to use these variables, angular will complain about types definition. To get around that, create a file called typings.d.ts inside of your *src/ folder and put the following in there:

declare var process: Process;

interface Process {
    env: Env
}

interface Env {
    SERVER: string
    PEER: string
}

interface GlobalEnvironment{
    process: Process;
}

Step 5: Usage

Once all the above steps were done, here is how I read the environment variables in my Angular application.

const BASE_URL = `http://${process.env.SERVER}/`

DockerFile

Like I mentioned earlier, I did this so that I can read the variables when docker builds my application. Here is what my dockerfile looks like:

FROM node:8.12 as build-deps
WORKDIR /home/ui/app
ENV SERVER=bennettnotes.com
COPY package.json ./
RUN npm install
COPY . ./
RUN npm run dist

See also