Frontend Builds 6: Configurable builds

Frontend Builds 6: Configurable builds

See all articles from the series

Idea

BaaS is fine so far if you're building your projects on exactly the same structure I did for building x-note. But right now, we're using Build as a Service, so it's time to make everything configurable.

Dumping all the default config values

BaaS should run successfully without any give user-config. That said, we need some kind of defaults. I've added a new JavaScript file to xplatform-build at src/defaults.js. It will expose all default config values as you can see below.

The script below is stripped in order to increase readability. See the entire file here in the repo

(function(module){

    function exportDefaultConfig(){
        var path = require('path');

        var cacheDir = path.join(process.env.HOME ||
            process.env.HOMEPATH || 
            process.env.USERPROFILE, 
            '.cache'),
            buildDir = path.join(process.cwd(), "desktop-build");
        return {
            folders: {
                mobile: {
                    root: 'mobile',
                    backlinkToProjectRoot: '..'
                },
                dist:{
                    root: 'dist',
                    styles: 'dist/styles',
                    scripts: 'dist/scripts'
                },
                temp:{
                    root: ".temp"
                }
            },
            filenames: {
                appScripts: 'app.js',
                appStyles: 'app.min.css',
                vendorStyles: 'vendor.min.css',
                vendorScripts: 'vendor.min.js',
                injectTargets: ['src/index.html']
            },
            sources: {
               // stripped to increase readability
            },
            options: {
                // stripped to increase readability
            }
        };
    }

    module.exports = exportDefaultConfig();
})(module);

All defaults where exported using the common module.exports mechanism.

Refactor gulp-task-files

Next I refactored of course all gulp-task-files, again go and check out all the changes over here. In summary the method signature must accept another parameter and all

(function(module) {
    'use strict';

    function RegisterTasks(gulp, tasks, config) {

        gulp.task('private:build', function(done) {
            tasks.inSequence(
                'private:clean',
                'private:app:templates', [
                    'private:vendor:css',
                    'private:vendor:js',
                    'private:app:css',
                    'private:app:js'
                ],
                'private:app:html',
                done
            );
        });

        gulp.task('private:clean', function(done) {
            // replace all strings with config properties
            tasks.del.sync(config.sources.del, config.options.del);
            done();
        });

        /*
         * stripped to ensure readability
         */
    }

    module.exports = {
        init: RegisterTasks,
        docs: [
        // stripped to ensure readability
        ]
    };

})(module);

Refactor the gulpfile

Last but not least the src/gulpfile.js has to be updated. There are a few things going on here

  • add the possibility to pass a config to the gulpfile.js
  • load the default config
  • override default config with user-config
  • pass merged config to gulp-task-files' init method

See the entire gulpfile.js here

(function(module){

    function XplatformBuild(userConfig){
        var gulp = require('gulp');

        var tasks = {
            del: require('del'),
            concat: require('gulp-concat'),
            inject: require('gulp-inject'),
            cssmin: require('gulp-cssmin'),
            ngAnnotate: require('gulp-ng-annotate'),
            ngTemplateCache: require('gulp-angular-templatecache'),
            rename: require('gulp-rename'),
            shelljs: require('shelljs'),
            uglify: require('gulp-uglify'),
            path: require('path'),
            NwBuilder: require('nw-builder'),
            inSequence: require('run-sequence')
        };

        var override = function(original, uConfig){
            for(var p in uConfig){
                if(typeof(uConfig[p]) !== 'object' || Array.isArray(uConfig[p])){
                    original[p] = uConfig[p]
                }else{
                    override(original[p], uConfig[p]);
                }
            }

        };

        var config = require('./defaults.js');
        override(config, userConfig);

        var customGulpTasks = require('require-dir')('./gulptasks');

        for (var gulpTask in customGulpTasks) {
            customGulpTasks[gulpTask].init(gulp, tasks, config);
        }

        gulp.task('help', function() {
            console.log('Execute one of the following commands\n');
            for (var gulpTask in customGulpTasks) {
                if (!customGulpTasks[gulpTask].hasOwnProperty('docs')) {
                    continue;
                }
                customGulpTasks[gulpTask].docs.map(function(doc) {
                    console.log("gulp " + doc.task + " - (" + doc.description + ")");
                });
            }
            console.log('\n');
        });
    }

    module.exports = XplatformBuild;
})(module);

Refactor the usage in x-note

After refactoring your BaaS (here xplatform-build), of course the application itself has to be refactored. This is the easy part, there is just a small updated for the gulpfile.js. See the () behind the require call

require('xplatform-build')();  

If you'd like to provide a custom user-config just pass it as json object to the call like shown below.

// USE THIS SNIPPET ONLY IF YOU'D LIKE TO OVERRIDE 
// DEFAULT SETTINGS
require('xplatform-build')({  
    options: {
        cordova: {
            runCommands: [
               'cordova run ios', 
               'cordova run android', 
               'cordova run windows'
            ]
        }
    }
});

Again, see xplatform-build here and the BaaS branch of x-note over here

Comments

comments powered by Disqus