Declarative Build Configurations

By  on  

Some time ago I posted an article how you can build apps faster using a build tool called Angus. In the meantime the tool has gotten a whole lot better, embracing the concept of declarative build configurations. In this article I would like to show you what that means and how Angus can help you build web apps in a much faster way.

In The Restaurant

Gordon Ramsay

Imagine for a second you're sitting in a restaurant. You take a look at the menu. You decide that you would like a Pizza Vegeta today, because you're feeling healthy. Hmm!

Next, you stand up from your table. You walk to the kitchen. You start to delegate.

"You there! Take some dough and make it flat and round."

"And you! Chop some onions, tomatoes and bell peppers."

"Now you, grab the tomato sauce and cheese and put them on the dough."

"Put all those vegetables on the pizza and then put it in the oven for ten minutes!"

After ten minutes, you come back. You put the pizza on your plate, walk to your table and start eating.

GulpJS: A Case Study

Let's wake up, and take a look at a common build tool configuration from GulpJS.

gulp.task('clean', function(cb) {
  del(['build'], cb);
});

gulp.task('scripts', ['clean'], function() {
  return gulp.src(paths.scripts)
    .pipe(sourcemaps.init())
      .pipe(coffee())
      .pipe(uglify())
      .pipe(concat('all.min.js'))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('build/js'));
});

gulp.task('images', ['clean'], function() {
  return gulp.src(paths.images)
    .pipe(imagemin({optimizationLevel: 5}))
    .pipe(gulp.dest('build/img'));
});

gulp.task('watch', function() {
  gulp.watch(paths.scripts, ['scripts']);
  gulp.watch(paths.images, ['images']);
});

gulp.task('default', ['watch', 'scripts', 'images']);

If you compare this configuration with the absurd restaurant scene, it's essentially not that different. You're telling Gulp what to do, how to do it and when and where to get your compiled files.

Can we do better than that? What if there was a way to tell Gulp, "Hey, today I'd like a Pizza Vegeta."?

What if there was a tool, where you could say "Today I'd like to have an app that uses AngularJS, some bootstrap, karma as test runner, and hmmmm... I'll have Sass as my CSS compiler this time."

Angus, A Declarative Build Tool

angus

Having built a ton of apps, I've always found myself having to declare the same tasks over and over again, although they essentially stayed the same across my apps. Out of frustration with the state of things, I decided to create a tool called Angus that makes build configurations declarative.

Take a look at a common Angus configuration.

{
    bower: {
        packages: [
            'angular',
            'threejs',
            'Keypress',
            'underscore@1.7.0',
            'angular-ui-router',
            'hammerjs'
        ],
        filesNeeded: {
            js: [
                'angular/angular.js',
                'angular-ui-router/release/angular-ui-router.js',
                'Keypress/keypress.js',
                'hammerjs/hammer.min.js',
                'threejs/build/three.js',
                'underscore/underscore.js'
            ]
        }
    },
    usesAngularJS: true,
    testRunner: 'karma',
    cssCompiler: 'less'
};

In essence, I'm telling Angus which bower packages my app needs and which files to actually use from those bower packages. Next I'm declaring it uses AngularJS, Karma as its test runner and Less as its CSS compiler.

That's it. There are no other hidden configuration files. I just run angus dev from the command line and my app launches in the browser, ready to go.

Angus takes care of everything. It installs your bower packages, minifies your files, compiles your CSS, watches for changes and launches your app in a browser. But there's a lot more features.

Convention Over Configuration

Angus applies the concept of convention over configuration so that it doesn't burden the user with making unnecessary choices such as where to store the distributed files. For one, it requires you to layout your source files in a way that's common for web apps.

hello-world/
    bower_components/
    src/
        assets/
        style/
        core/
        index.html
    angus.config.js

This makes things a lot simpler. By having your source files structured in the same way for every app, Angus can automatically build your app without you having to specify where your source and library files are.

Next, all underlying tasks use this folder structure to build your app. All common tasks are pre-configured, Angus just tells them whether to execute or not based on your config file. Again, it's declarative.

In addition, it's a lot easier to maintain. For example, if you wanted to switch to another CSS compiler, it's simply a matter of enabling it in your config file.

Quick Start

Getting started with Angus is easy. Just install it with npm install -g angus.

Next, create a sample app by doing angus create hello-world. This will create a folder hello-world.

Inside this folder, run angus dev and open your browser to visit http://localhost:9000/.

That's it! For further information, please refer to the detailed readme on GitHub.

Conclusion

I hope that this article has given you new insights in how declarative build configurations can help you focus your efforts on your app and not your build process. Angus has gotten a lot of good feedback so far, and I invite you to try it out and make an opinion for yourself. If you have any questions I will be happy to answer them in the comments section below.

Nick Janssen

About Nick Janssen

Nick Janssen is a full-stack web developer with a passion for creating cool applications, originally from Belgium.

Recent Features

  • By
    Introducing MooTools Templated

    One major problem with creating UI components with the MooTools JavaScript framework is that there isn't a great way of allowing customization of template and ease of node creation. As of today, there are two ways of creating: new Element Madness The first way to create UI-driven...

  • By
    JavaScript Promise API

    While synchronous code is easier to follow and debug, async is generally better for performance and flexibility. Why "hold up the show" when you can trigger numerous requests at once and then handle them when each is ready?  Promises are becoming a big part of the JavaScript world...

Incredible Demos

  • By
    Using jQuery and MooTools Together

    There's yet another reason to master more than one JavaScript library: you can use some of them together! Since MooTools is prototype-based and jQuery is not, jQuery and MooTools may be used together on the same page. The XHTML and JavaScript jQuery is namespaced so the...

  • By
    Implement the Google AJAX Search API

    Let's be honest...WordPress' search functionality isn't great. Let's be more honest...no search functionality is better than Google's. Luckily for us, Google provides an awesome method by which we can use their search for our own site: the Google AJAX Search API.

Discussion

    Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!