Use aliasify to include configurations in your web application

As I build more web applications, one problem that I keep running into is how to include application configurations into the application source code.

What do I mean by configurations?

They include application-specific settings such as the application name, API URL, debug mode etc. These are metadata to the application, similar to the metadata contained in package.json for a Node module.

As I develop most of my applications locally, some of these settings will differ when the application is served on localhost versus when served in production. For eg., I usualy use a staging API server for local development and then a production server for deployment.

I could certainly hardcode these settings into the source code right?

The fact that I need 2 (or more) environment-specific versions of these settings make them difficult to be hardcoded. Furthermore, as a developer, I feel a little “dirty” when I hardcode these settings. Ideally, they should be declared in a JSON file somewhere, just like package.json.

There must be other solutions out there!

Surprisingly, there isn’t a good straight forward solution out there, as far as I know (if you know of one, please leave a comment). Here are a few worth mentioning:

One can follow the approach outlined by Addy Osmani in making environment-specific builds with build tools and use some sort of string replacement plugin. However, this will introduce some ‘not-so-pretty’ delimiters in the codebase, such as @@foo used by grunt-replace.

Henrik Joreteg’s clientconfig is another elegant solution and very close to what I have in mind, however it relies on a server component to set all the configurations in a cookie. This is not a hard requirement, but is not feasible for a static site running on a simple file server (such as Github Pages) like this blog.

Another attempt at solving this problem

If you are using browserify to bundle your JavaScript code, this might be a good solution for you.

Using aliasify, you can require your config, which is declared in a config.json file like this:

{
			  "API_URL": "http://example_server.com/api",
			  "env": "development"
			}
var config = require('config');
			
			console.log(config.API_URL); //prints out API_URL
			if (config.env === 'development') {
			  // do something specifically in development mode
			}

To declare this transformation, you can add the following section to package.json:

{
			  "aliasify": {
			    aliases: {
			      "config": "./config.json"
			    }
			  }
			}

Pretty simple, right?

Environment-specific configs

We can make this even better, by allowing for environment-sepcific configs. To do that, I recommend using a build tool like grunt or gulp. I am sure there is probably a way to do it with just the simple browserify command line interface, but using browserify programmatically makes things a lot easier.

Here’s an example of how I am using this in a recent project:

// gulpfile.js
			
			// enable development mode
			var dev = false;
			gulp.task('enable-dev-mode', function () {
			  dev = true;
			});
			
			gulp.task('scripts', function () {
			  // set up browserify bundle in here
			  // see https://github.com/gulpjs/gulp/blob/master/docs/recipes/browserify-uglify-sourcemap.md
			
			  // aliasify config
			  var aliasify = require('aliasify').configure({
			  aliases: {
			    'config': './config' + (dev ? '.dev' : '') + '.json'
			  },
			  configDir: __dirname
			  })
			  bundler.transform(aliasify);
			});

In this approach, aliasify will automatically use config.dev.json for development environment and config.json for production one.

A similar approach could be taken when using grunt-browserify. In fact, it is probably easier to do environment-specific stuff with grunt due to its ability to declare a task target.

There you have it, a simple approach to accessing environment configuations in your project that is made possible by browserify.

What’s bad, what’s good, what could be better?

This solution’s downside is relying on browserify (and possibly a build system), which might not be applicable for an older project. If you use RequireJS/AMD, I imagine it’d be similarly easy to include such a config file using the JSON plugin.

One possible improvement to this solution is allowing the ability to cascade configs across environment. For example:

In config.json

{
			  "appName": "FooBar",
			  "apiUrl": "http://foobar.com/api"
			}

And then config.dev.json just “extend” it without redeclaring common configs:

{
			  "apiUrl": "http://localhost:3000"
			}

This is currently not possible with using aliasify. I have implemented a similar version of this as a grunt task for tobiko, but it’s not polished enough to be used by others yet. I will update this space if and when this becomes available.

comments powered by Disqus