If you develop a website that uses multiple environments such as development, staging and production you probably have a configuration file of sorts to handle things like database settings, mail server credentials, and so on for your backend system.
But how do you handle such variables in the front-end? Specifically, in an AngularJS App?
For instance, you might have a seperate API you're talking to for your content, which has a different location locally, than on your production server. Or you might want to do some debugging or verbose output, based on what environment you're on.
In this post I'll show you how to set this up automagically using Grunt and ngConstant.
Malte was so kind as to provide an updated configuration for the ngconstant 0.5.0 version. The example code in the post has been updated accordingly.
I'll assume you're familiar with Grunt and have set it up to aid your workflow. If not, there's plenty of tutorials out there to get this going.
This Grunt plugin takes care of the dynamic generation of your constants. Grab it here, or simply install it by doing:
npm install grunt-ng-constant --save-dev
Now that you have all you need, let's set it up! Open up your Gruntfile.js
, and inside the grunt.initConfig
section add the following:
ngconstant: {
// Options for all targets
options: {
space: ' ',
wrap: '"use strict";\n\n {\%= __ngModule %}',
name: 'config',
},
// Environment targets
development: {
options: {
dest: '<%= yeoman.app %>/scripts/config.js'
},
constants: {
ENV: {
name: 'development',
apiEndpoint: 'http://your-development.api.endpoint:3000'
}
}
},
production: {
options: {
dest: '<%= yeoman.dist %>/scripts/config.js'
},
constants: {
ENV: {
name: 'production',
apiEndpoint: 'http://api.livesite.com'
}
}
}
},
This tells Grunt about your environments. Each target is told where to write the config file to, and inside constants
you define your environmental variables you wish to use in your Angular App.
Next up, we need to tell Grunt when to write this config file. Depending on your Gruntfile you will probably have a section that tells it to run a local server so you can develop your site. Mine usually looks like this:
grunt.registerTask("serve", function (target) {
if (target === "dist") {
return grunt.task.run(["build", "connect:dist:keepalive"]);
}
grunt.task.run([
"clean:server",
"ngconstant:development", // ADD THIS
"bower-install",
"concurrent:server",
"autoprefixer",
"connect:livereload",
"watch",
]);
});
Here we tell Grunt to build the ng-constants for the development area. So whenever you boot up the local environment with grunt serve
, it will write out the config file for the development target.
Likewise, we want to do the same for our production environment. Best place to do that is in our grunt build
task:
grunt.registerTask('build', [
'clean:dist',
'ngconstant:production', // ADD THIS
'bower-install',
.. // other build tasks
]);
When Grunt runs the task, a config file is generated, with our constants:
"use strict";
angular
.module("config", [])
.constant("ENV", {
name: "development",
apiEndpoint: "http://your-development.api.endpoint:3000",
});
So, now that we have a dynamic config.js
file based on where we are, let's see how we can use it in our AngularJS App.
First thing to do is add the config file to our index.html
<script src="/scripts/config.js" />
Next, we can inject it into our app:
var app = angular.module("myApp", ["config"]);
And now, since config.js exposes an object ENV
which is injected, whenever we need our ENV variables we can simply use them in our controllers by doing:
angular.module("myApp").controller("MainCtrl", function ($scope, $http, ENV) {
// ENV is injected
$scope.login = function () {
$http
.post(
ENV.apiEndPoint, // Our environmental var :)
$scope.yourData
)
.success(function () {
console.log("Cows");
});
};
});
And there you have it. Environmental variables in your front-end. It might look like a lot of work, but once you've set it up it's easy to extend the variables and duplicate environments to match your needs.
Happy coding.