OS Environment variables with Angular 7 and Custom Webpack

Spread the love

For a long time, server-side development enjoyed a rich set of Toolkits for development, build and deployment. One of the most convenient features is the ability to externalize configuration from the actual source code. API URL, secrets, threshold limits etc can be configured outside the actual code and exposed via Operating system’s environment variables. This promotes a good practice of immutable build packages. These builds can be promoted without a need to make modification in the actual code to adapt to a changing environment.

OS Environment variables with Angular 7 and Webpack
OS Environment variables with Angular 7 and Webpack

We have been witnessing an era wherein the magical power of build tools is no more restricted to Server side development. Tools like Grunt, Yeoman, Gulp, Webpack, Browserify etc. have redefined how today’s modern User Interfaces are actually built.

I had a problem

I was working on a Angular 6 Project which interacts with Server side API and it is also integrated with an IAM (Identity Access Management) solution. Naturally it requires certain values which differ from environment to environment. I didn’t realize a problem as long as I was developing and testing my application locally. But soon, when I started promoting it on Test servers, I hit the first roadblock – configuration.

With Angular 6, I used the “environments” feature. It looks sufficient on the surface. You can create a dedicated configuration file for each environment and then use a command like below to build a project matching to that environment.

ng build –configuration=production

Don’t have time to read article, then you can watch it in action here.

Something is not right

I was not quite comfortable having each environment configuration buried with Code. My git repository was aware of how many configurations I do have. Sometimes we do create an environment for temporary reasons and want to quickly destroy it once those reasons are fulfilled. Creating a configuration for such an environment and adding it to repository was overkill.

With my polyglot experience, I realized that Server-side development have solved this problem with the help of environment variables. For e.g. refer to following property file configuration in Spring

payment.gateway.url=${PAYMENT_API_URL:https://www.dummypay.com}

The syntax is self explainatory. Look for an environment variable – PAYMENT_API_URL and assign its value to the property. If the variable is not found, initialize the property with default value.

If not similar can it be better?

I really enjoy coding APIs because of the strong tooling system. The ease that it provides to simplify complex looking things and the power to port an application from one environment to another without much hassle. The usage of environment variables is very appealing and provides numerous benefits . I needed something similar in Angular build. Instead of hardcoding values inside environment.XXX.ts files, I needed an approach to keep one file for development and another with placeholders.

As they say,

Necessity is the mother of Invention.

That’s bit of exaggeration. 😛 There was no need to invent something, but to find a right set of build plug-ins to achieve desired results. I came across few articles and posts which eventually led me to a webpack plugin – @angular-builders/custom-webpack

Eureka!!!

While I am still learning webpack and Angular 7, I realised that webpack has pretty strong features. The @angular-builders plug-in is definitely an answer to my problem. The plug-in enables an option to configure webpack plug-in and perfoms all the default build operations of Angular build. With the help of webpack, accessing environment variables requires few lines of code. Let me explain the steps one by one.

Configure Dependency

To see the plug-in in action, create an Angular application using Angular CLI. The command line syntax looks like below

ng new ng-environment

Once all the skeleton project is configured and all the dependencies are downloaded. Make sure to test the application by executing “ng serve” command. This is required to ensure there are no bugs in the existing build and everything works as expected.

Once you are assured of Angular Application is working as expected, go to the command prompt or Terminal winow in Visual Studio code. Make sure that you are at the root location of your project (Inside a folder where package.json resides). Execute the following command to download the new module dependency

npm install –save-dev @angular-builders/custom-webpack

Note the –save-dev argument is essential. The new module is only required to build a project and not for runtime. This also ensures that there is no overhead on the Angular application runtime.

Webpack plug-in configuration

This step is broken into two parts – Modifying angular.json and definition of custom webpack configuration

Open angular.json file located at the root of the Angular project. Locate the build section (available inside “projects” > “ng-environment” (project name) > “architect” > “build”

Change the existing builder plugin to

@angular-builders/custom-webpack:browser

Also under options section, add following configuration

“options”: {
customWebpackConfig”: {
path”:”custom-webpack-config.js”
},
…..

Schema definition for Environment Variables

Since we are using Typescript to write Angular code, we must declare Schema to define the list of environment variables. To proceed with the definition, create typing.d.ts file under src folder. The content of the file should look like following.

declare var $ENV: ENV;
interface ENV { API_URL: string;}

Webpack Plug-in

In the earlier step we provided reference of custom-webpack-config.js. The file will have logic to access the environment variables. Have a look at the following code

const webpack = require(‘webpack’);
module.exports = {
plugins: [
new webpack.DefinePlugin({
$ENV: { API_URL : JSON.stringify(process.env.API_URL) }
})
]};

The important things to note here is that

  • The $ENV key matches to the variable defined in typing.d.ts
  • The name of the API_URL matches to the attribute defined in ENV schema.
  • Environment variable is accessed using NodeJS API – process.env

Production environment – environment.prod.ts

This is the final step. The environment variables can be referenced into our configuration file. I will recommend to leave environment.ts file with development configuration and modify environment.prod.ts. The modified file should look like below

export const environment = { production: true, API_URL: $ENV.API_URL};

Congratulation!!! you have made your application portable across environment. No more fiddling with environment.XXX.ts files. Just define OS environment variables and build your application with

ng build –configuration=production

Leave a Comment.