Using Environment Variable With Angular

Developing an application can be done with just localhost URLs, but when it comes to building and deploying software, we need to change these URLs to appropriate values.

While working with Angular, it might be painful to replace all these values without making any mistakes or complex configurations. Some guides say it can be done by configuring “Webpack,” but I find them quite confusing. Here is a workaround solution that will work for all bundlers and can also work with Docker builds.

The method I will tell you about will work with all NodeJS-based projects. You can probably adapt this method to other languages.

Firstly, we need to determine which parameters should be replaced for different environments. It is mostly backend HTTP request URLs that need to be changed. We will create a file for templating these variables.

Create a new folder under src/ named environments and a new file called environment.template.ts. Add your variables as shown below. You can add as many variables as you want.

export const environment = 
{
    production: '${IS_PRODUCTION}',
    API_URL: '${BACKEND_URL}${BACKEND_PORT}'
};

After you have created the template file, let’s add a JS file for replacing these values. This script will go through your environment variables and replace their values with them. What it does is similar to the envsubst command on Linux. 

//replace_environment_variables.js file
const fs = require("fs");

// this will get argument from command line
let config = process.argv[2];

// read template file as string
let template_environment = fs.readFileSync("./src/environments/environment.template.ts").toString();

// for every keys you have defined on environment this will loop over them and replace the values accordingly
Object.keys(process.env).forEach(env_var => {
    template_environment = template_environment.replaceAll(`${${env_var}}`,process.env[env_var])
});

// if config is given use it on file name.
if(config)
    fs.writeFileSync(`./src/environments/environment.${config}.ts`, template_environment);
else
    fs.writeFileSync("./src/environments/environment.ts", template_environment);

Lastly, we need to run this script before the “ng serve” or “ng build” command. To do that, we need to add commands to NPM scripts inside package.json. Add “replace-vars” to the scripts section of the package.json file. You can pass arguments while running this command like `npm run replace-vars prod.` This will create an environment file with a given input, such as environment.prod.ts. 

"scripts": {
    "ng": "ng",
    "replace-vars": "node ./src/environments/replace_environment_variables.js",
    "start": "npm run-script replace-vars && ng serve",
    "build": "npm run-script replace-vars && ng build",
  }

You can also combine this script with ng build and ng serve. It should run just one time to replace those variables so you can skip combining commands, as shown above.

Inside the replace_environment_variables.js file, you can get your variables from wherever you want, connect to a database, or make a request to an API; it is your choice as your requirement goes.

Let’s see how can we use this logic inside a Dockerfile. First, we need to define arguments that will be used for replacing environment.template.ts.

FROM node:latest as node

ARG BACKEND_API_PORT 
ARG BACKEND_API_URL
WORKDIR /app

ARG BACKEND_URL=$BACKEND_API_URL
ARG BACKEND_PORT=$BACKEND_API_PORT

RUN npm install
RUN npm run build --prod

Now, we can pass these arguments as docker build-arg. You can either use your environment variables where you build your docker images, or we can pass them manually. 


# For linux
docker build --build-arg BACKEND_API_URL=$BACKEND_API_URL --build-arg BACKEND_API_PORT=:$BACKEND_API_PORT -t docker-image-name:latest .

# For windows
docker build --build-arg BACKEND_API_URL=$Env:BACKEND_URL --build-arg BACKEND_API_PORT=:$Env:BACKEND_PORT -t docker-image-name:latest.

# Manuel variable passing
docker build --build-arg BACKEND_API_URL=http://some-cool-address.com/api --build-arg BACKEND_API_PORT=:8443-t docker-image-name:latest.

After the build is done, you can check if the container it is replaced correctly by running the container with the below command.

docker run -it container-id bash
cat src/environments/environment.ts

You should see your input from the docker build command.


Source link