Tutorial

Properly Set Environment Variables for Angular Apps with gulp-ng-config

Draft updated on Invalid Date
Default avatar

By The Pub

Properly Set Environment Variables for Angular Apps with gulp-ng-config

This tutorial is out of date and no longer maintained.

Introduction

Configuring environment variables (env vars for short) in Angular is now much easier to do. In this tutorial, we shall set environment variables for an AngularJS app using gulp-ng-config.

This tutorial is relatively easy to follow if you have had experience with environment variables, Gulp, or AngularJS.

Why You Should Use Environment Variables

Using env vars enables you to separate your source code from your application configuration (or config, for short). This is good practice because config varies substantially across your app deploys, but your code generally does not.

Some benefits you reap by employing env vars are:

  1. You can dynamically assign env vars, depending on the different types of environments your app resides in. The needs across your environments(development, staging, production, etc.) greatly differ. Hence, they require unique configs. For example, your development environment may use localhost for its API, while your production uses a live API hosted on a remote server.
  2. Switching between one environment and another is hassle-free, by just changing the name of your environment. For instance, on your continuous integration service, your env may be testing, while on your hosting provider, it changes to production.
  3. Sharing your code publicly or making it open source is easily achieved, without compromising your application’s security. Sensitive credentials and resource details are safely stored away in your env vars, while your code is on a public repository.
  4. Scaling and configuring your application can be done automagically. Having a static config greatly limits how much your application can scale. If your config is separate from your code, changes can be made to the config, to scale the number of resources your application consumes, depending on its load.

What can you put into an environment variable?

Contents of your config and env vars may include things like:

  1. External API URLs that your app queries e.g., Google Maps API
  2. Credentials e.g., Amazon S3 secret keys and access ids
  3. Resources e.g., build pack URL
  4. Deploy specific values e.g., whether to enable deletion or debug logging, the environment type

Now that we have got the basics down on environment variables, we can now write our first .env file.

Prerequisites

To start on this project you will have to have the folowing installed:

Scaffolding Our App

We need to lay the groundwork for our app first. The contents of our project will include:

├── ./.bowerrc
├── ./.env
├── ./.gitignore
├── ./app
│   ├── ./app/app.less
│   ├── ./app/head.jade
│   ├── ./app/index.jade
│   └── ./app/scripts
│       ├── ./app/scripts/application.js
│       ├── ./app/scripts/config.js
│       ├── ./app/scripts/controllers.js
│       └── ./app/scripts/services.js
├── ./bower.json
├── ./config.js
├── ./gulpfile.js
├── ./index.js
└── ./package.json

We shall start by creating the:

  1. package.json: Run $ npm init and follow all the required steps to completion. The name of our app is ngEnvVars.
  2. bower.json: Run $ bower init and follow all the steps to completion using the same app name as above.
  3. .bowerrc: This will specify to bower where to store all the bower components it installs. Its contents include:
{
  "directory": "./public/lib"
}

Writing your .env File

A .env file is made up of environment variables, one on each line, that take this format:

ENV_VAR_NAME=env_var_value

Create a new folder named angular-env-vars on your terminal, change the directory to it and create your .env file. The contents of your .env file should look something like this:

API_URL=https://example.com
API_TOKEN=myawesomeapitoken
APP_DEBUG=false
APP_ENV=development

Keep your .env File Private

The contents of a .env file are quite sensitive and should hence be kept private. Be sure to leave it out of your version control system.

You do this by adding it in your .gitignore. This is a small sample of the contents of a .gitignore, but a more detailed file can be found here.

# Config Files
.env

# Runtime data
node_modules/
public/

Installing Our Dependencies

To create our sample app, we shall use jade and less, which make writing HTML and CSS much easier. Our app shall require a few packages to run:

  • browser-sync: to create the server that will host our app
  • browserify: to bundle our different angular modules together
  • dotenv: to load our environment variables
  • gulp: the task runner that automates some of our jobs
  • gulp-bower: installs our bower components
  • gulp-jade: converts our jade files to HTML
  • gulp-less: converts our less files to CSS
  • gulp-ng-config: creates our angular environment constants
  • vinyl-source-stream: to aid browserify

Let’s now install them.

  1. npm install browser-sync browserify dotenv gulp gulp-bower gulp-jade gulp-less gulp-ng-config vinyl-source-stream --save

In addition to the above, we will need to install angular and angular material as our UI framework and font-awesome for our icons, using bower.

  1. bower install angular angular-material font-awesome --save

We can now get to writing the code.

Env Vars for Different Environments

Some of your environment variables are shared between your various environments, but there are others that are unique to a particular environment. For instance, on your production environment, may require a BUILDPACK_URL to be able to build our app. Locally, however, we don’t need it.

We can group relevant env vars of a particular environment together. To do this, we will create a file that returns an object with each environment’s env vars.

Create a file called config.js on the base directory. We shall use this file to generate the config.json file that gulp-ng-config takes in as input.

// Shared env vars in all environments
var shared = {
  apiUrl: process.env.API_URL || "http://localhost:3000/api",
  apiToken: process.env.API_TOKEN,
  debug: process.env.DEBUG || true
};

//
var environments = {
  development: {
    ENV_VARS: shared
  },
  staging: {
    ENV_VARS: shared
  },
  production: {
    ENV_VARS: shared
  }
};
environments.production.buildpack  = process.env.BUILDPACK_URL;

module.exports = environments;

The Gulp File

Gulp will allow us to automate tasks like starting our server and bundling our angular files together. Our main use for gulp here is to load our env vars from the .env and generate our angular env constants.

First, we’ll create a gulpfile.js in the base directory. Within it we shall have six main tasks:

  • jade: to compile our jade to html
  • less: to compile our less to css
  • browser-sync: to spun our server
  • browserify: to bundle our modules
  • ng-config: to create our angular config
  • bower: to install our bower dependencies
  • watch: to watch for any changes we make and rebuild our app

In addition, we will add two other tasks that build on the above, namely build and the default task. For the sake of brevity, I will demo the loading of env vars and the creation of the angular env constants only. However, you can still check out the rest of the full gulp file.

// If the app environment is not set, we default to development
var ENV = process.env.APP_ENV || 'development';

// Here, we use dotenv  to load our env vars in the .env, into process.env
if (ENV === 'development') {
  require('dotenv').load();
}

// Our dependencies and paths of files we use
var gulp = require('gulp'),
  gutil = require('gulp-util'),
  source = require('vinyl-source-stream'),
  ngConfig = require('gulp-ng-config'),
  path = require('path'),
  fs = require('fs'),
  config = require('./config.js'),
  paths = {
    public: {
      path: 'public/',
      script: './public/js/',
      lib: './public/lib/'
    },
    app: {
      jade: ['!app/shared/**', 'app/**/*.jade'],
      styles: 'app/styles/*.+(less|css)',
      staticFiles: [
        '!app/**/*.+(less|css|js|jade)',
        '!app/images/**/*',
        'app/**/*.*'
      ],
      scripts: {
        app: './app/scripts/application.js',
        all: './app/scripts/**/*.js'
      }
    }
  };

/*
 *  We first generate the json file that gulp-ng-config uses as input.
 *  Then we source it into our gulp task.
 *  The env constants will be a saved as a sub-module of our app, ngEnVars.
 *  So we shall name it ngEnvVars.config.
 */
gulp.task('ng-config', function() {
 fs.writeFileSync('./config.json',
      JSON.stringify(config[ENV]));
  gulp.src('./config.json')
    .pipe(
      ngConfig('ngEnvVars.config', {
        createModule: false
      })
    )
    .pipe(gulp.dest('./app/scripts/'))
});

/*
 * Browserify bundles our Angular env constants,
 * services and controllers together into one file.
 * So, ng-config has to run first, to generate the angular env contants.
 * We shall add ng-config as a dependency of browserify, so that it runs before it.
 */
gulp.task('browserify', ['ng-config'], function() {
  return browserify(paths.app.scripts.app).bundle()
    .on('success', gutil.log.bind(gutil, 'Browserify Rebundled'))
    .on('error', gutil.log.bind(gutil, 'Browserify ' +
      'Error: in browserify gulp task'))
    .pipe(source('application.js'))
    .pipe(gulp.dest('./public/js/'));
});

gulp-ng-config takes two parameters:

  • module name: Our name here is ngEnvVars.config where ngEnvVars is the name of the angular app, while config denotes the content of our module. You can, however, name it whatever you may like.
  • configuration: These are the options we would like to specify for the module. For example, here, we use createModule and make it false. It indicates that we will not want a new module created for the env constants, but instead, we will define it on our own later in the code. For a full list of options, you could use, check out the gulp-ng-config npm page.

We will save the resulting config file in app/scripts/.

Our Angular App

We will break up our angular app into four main parts:

  • The main angular app
  • The controller for our single page
  • The service that uses our env constants
  • The config file generated by gulp-ng-config.

These will all be under the app/scripts folder. In addition to this, we shall have our index.jade as our main page, head.jade to hold all our dependency and styling links, and lastly, app.less for our styling.

These will be under the app folder. Check out the jade and less references.

The resulting folder structure will be as follows:

app
├── app.less
├── head.jade
├── index.jade
└── scripts
    ├── application.js
    ├── config.js
    ├── controllers.js
    └── services.js

The Main Angular App

Only two things are involved in creating our main app. First, we define all our dependencies (services, controllers, configs). Then we define our app, with it dependencies, both defined or installed.

We will do this in the app/scripts/application.js file. We will add the config.js first, then the services.js, and finally the controllers.js. This is because the config is used by the services and the services used by the controllers, and hence should be loaded in that order.

(function() {
  'use strict';
  // Sub-modules of the app
  angular.module('ngEnvVars.controllers', []);
  angular.module('ngEnvVars.services', []);
  angular.module('ngEnvVars.config', []);

  // Constants
  require('./config.js');

  // Services
  require('./services.js');

  // Controllers
  require('./controllers.js');

  // Definition of the ngEnvVars app and its dependencies
  window.app = angular.module('ngEnvVars', [
    'ngEnvVars.config',
    'ngEnvVars.controllers',
    'ngEnvVars.services',
    'ngMaterial'
  ]);
}());

How our Config File Will Look Like

If you have created your .env, config.js, and gulpfile.js, we are now ready to generate our angular config file. Note that, the name of our angular config file will be the same as the name of the config.json file generated when we run gulp. Remember that this file will be saved in app/scripts/.

Let’s now get to generating the file.

  1. gulp ng-config

Running this command will generate the file app/scripts/config.js, which should look like this:

angular.module("ngEnvVars.config")
  .constant("ENV_VARS", {
    "apiUrl": "https://example.com",
    "apiToken": "myawesomeapitoken",
    "debug": true,
    "env": "development"
  });

A Service that Uses our Env Constants

So now that we have our env vars, we could use them in a service. We shall make a service that logs a message depending on whether APP_DEBUG has been set to true in the .env. Let’s call this service log. It shall need 3 things to work:

  • [$log](https://docs.angularjs.org/api/ng/service/$log): An angular service for logging messages to the console.
  • ENV_VARS: The constant in which our environment variables are stored.
  • [$mdToast](https://material.angularjs.org/latest/demo/toast): An angular material toast service that we will use to inform the user when debugging has been set to false.

The resultant service takes this form:

angular.module('ngEnvVars.services')
  .factory('log', ['$log', 'ENV_VARS', '$mdToast',
    function($log, ENV_VARS, $mdToast) {
      /* Calling this service returns a function that takes in
       * the type os a message and the message itself
       */
      return function(type, msg) {
        /* If debug has been set to true, logging will be enabled.
         * Otherwise, a toast will be displayed informing the user that
         * this feature is disabled for that particular environment
         */
        if (ENV_VARS.debug === true) {
          if (type) {
            $log[type](msg);
            $mdToast.showSimple('Just printed a ' + type +
              ' message to the console');
          } else {
            $mdToast.showSimple('You have to specify' +
              ' a message type first');
          }
        } else {
          $mdToast.showSimple('This environment is not ' +
            'configured to log anything at this time');
        }
      };
    }
  ]);

Finally, our Controller

Our config file has been used in our service. Now it’s time to use our service in our very simple controller.

angular.module('ngEnvVars.controllers')
  .controller('HomeCtrl', ['$scope', 'log', 'ENV_VARS',
    function($scope, log, ENV_VARS) {
      // This will contain our envars
      $scope.envVars = ENV_VARS;

      // This will log a message to the console
      $scope.log = function() {
        log($scope.logType, 'You have logged a ' +
          $scope.logType + ' message to the console');
      };
    }
  ]);

The View: the Icing on the Cake

I’ve broken down our view into two parts: the head and the body. Our head (app/head.jade) will contain our links and scripts, while the body (app/index.jade) will be host to our page components.

The head:

base(href='/')
meta(charset='utf-8')
meta(name='description' content='angular app that accesses environment variables.')

// Angular material style
link(rel="stylesheet" href="lib/angular-material/angular-material.min.css")
link(rel='stylesheet' href="lib/font-awesome/css/font-awesome.min.css")
link(rel='stylesheet' type='text/css' href='app.css')

// Angular material javascript dependencies
script(src="lib/angular/angular.min.js")
script(src="lib/angular-aria/angular-aria.min.js")
script(src="lib/angular-animate/angular-animate.min.js")
script(src="lib/angular-material/angular-material.min.js")
script(src="lib/angular-resource/angular-resource.min.js")

// Our scripts
script(src="js/application.js")

title ngEnvVars

The main file containing both the body and the head(included as a file) :

doctype html
html(lang="en" ng-app="ngEnvVars")
  head
    include head
  body.bg-color.teal(flex ng-controller="HomeCtrl")
    div(flex layout="row" layout-align="center center" style="height: 100%")
      div(flex layout="column" layout-align="center center")
        span.fa-stack.fa-5x.md-margin
          i.fa.fa-circle.fa-stack-2x.text.yellow
          i.fa.fa-cogs.fa-stack-1x
        p.md-display-1 Angular Env Vars
        p with
        p.md-title gulp-ng-config
        // We display alist of our env constants here
        md-list(flex)
          md-divider.md-margin
          md-list-item.md-2-line(ng-repeat="(key, value) in envVars" ng-click="null")
            span.fa-stack.fa-lg.md-margin
              i.fa.fa-circle.fa-stack-2x.text.orange
              i.fa.fa-wrench.fa-stack-1x
            .md-list-item-text.layout-margin
              h3(layout="row")
                b Env Var: 
                p {{key}}
              p {{value}}
        // We use our log service here
        md-select(ng-model="logType" aria-label="Log Types")
          md-option(ng-repeat="type in ['log', 'info', 'warn', 'error', 'debug']") {{type}}
        md-button.bg-color.yellow(ng-click="log()") Log Some Error

All that’s left to do is style our page in the app/app.less file.

@teal: color("#4ABDAC");
@orange: color("#FC4A1A");
@yellow: color("#F7B733");
@grey: color("#DFDCE3");
* {
  margin: 0;
}

html,
body {
  height: 100%;
}

.text {
  &.orange {
    color: @orange !important;
  }
  &.teal {
    color: @teal;
  }
  &.yellow {
    color: @yellow;
  }
  &.grey {
    color: @grey;
  }
}

.bg-color {
  color: white;
  &.teal {
    background-color: @teal;
  }
  &.orange {
    background-color: @orange;
  }
  &.yellow {
    background-color: @yellow;
  }
  &.grey {
    background-color: @grey;
  }
  &.transparent {
    background-color: transparent;
  }
}

We are now set to launch our app. We do this by running:

  1. gulp

Running this command will automatically open the page in your default browser. This should lead to our awesome ngEnvVars page that should look like:

We now have access to the environment variables in the .env in our angular app. We have listed them on our page.

In your .env, set the APP_DEBUG to true at first. Run gulp and log a few messages to the console. To view the results on the console on Chrome, type CTRL+SHIFT+I or COMMAND+OPTION+I on a mac. You should see something like:

You can later set the APP_DEBUG to false. You could open another terminal tab and run:

  1. gulp ng-config

This command will regenerate the app/scripts/config.js. Our watch task in gulp will then rerun the app. When we now try to log to the console using our button, we shall get this message as a toast:

This concludes our tutorial on angular environment variables.

Conclusion

Environment variables are important resources that yield a lot of benefits when kept separate from the code. It is at times difficult to have access to them for use in an angular app, but with gulp-ng-config, obtaining them is a fairly easy process.

Hopefully, by the end of this tutorial, you will have a good grasp on how to do this.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us


About the authors
Default avatar
The Pub

author

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel