Frontend Builds 7: Conditional Build Tasks

Frontend Builds 7: Conditional Build Tasks

See all articles from the series


During the last post we made our BaaS configurable so that you can align the build to work with different folder structures, filenames or module configurations. Now it's time to take our build to another level. Many developers are using things like less, Sass to build their stylesheets. Others use CoffeeScript, BabelJS or TypeScript to build their JavaScript. Exactly those tasks are missing in our BaaS solution, so let's add them.

But, instead of adding all those tasks simple to our gulp.pipe chain, we want to put some more logic in our gulp-tasks to make the entire build more flexible.

To demonstrate how such a conditional build may look like, we'll add both CSS and JavaScript transpiling support to xplatform-build and let the developer choose for each and every project if she wants to use those tasks or not.

If you're already familiar with gulpjs. gulp-if may come into your mind. gulp-if works great for some situations but in my case I don't want to ship possible dependencies like gulp-sass to every system no matter if the consumer needs it or not. This leeds to a situation where gulp-if simply doesn't work!

Refactoring our BaaS

xplatform-build needs only some small refactorings to support all those conditional tasks. Let's extend each and every section of it right now.

Updating default options

First we need to provide a new section to our options object, which consumers can override later. To do so, simply append addOns: {} before the folders object like shown below

return {  
  folders: { /* stripped */},
  filenames: { /* stripped */},
  sources: { /* stripped */},
  options: { /* stripped */}

The new xplatform-build gulpfile

The gulpfile.js will receive some updates. First I've refactored the method for overriding config values a bit to be more powerful and renamed it to applyUserConfig. See applyUserConfig() below.

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

Another improvement is the possibility to automatically load Node.JS modules if they where installed in the current scope.

function loadCustomAddonIfInstalled(addOnName, tasks) {  
  try {
    tasks[addOnName] = require(addOnName);
  } catch (e) {
    console.error("module " + addOnName + " requested, but not installed!")
    console.log("run npm i " + addOnName + " --D");

The loadCustomAddonIfInstalled is called for every object in options.addOns which will be configured by xplatform-build consumers as you will read later.

Last but not least if installed and required gulp-empty which we'll use in a few minutes.

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'),
  empty: require('gulp-empty')

Notice that there is neither gulp-less nor any other transpiling module loaded at this point. See the entire gulpfile.js here in the repo.

Updating our web build to support transpiling

Next step is of course to support transpiling for both, JavaScript and CSS in our web build. See all the following changes to gulptasks/web.js.

Transpiling JavaScript

Let's take care about JavaScript, we'll add support for gulp-typescript, gulp-coffee and gulp-babel to your private:app:js gulptask.

For a single project only one of those three transpilers makes sense. But gulp is a little bit limited when it comes to skipping things that are not needed in a given context. That's why we added gulp-empty - which actually does nothing to files in the stream - to our project. It acts as a fallback task which will be invoked if the developer wont use any transpiler offered by xplatform-build.

See the refactored private:app:js task below. The task itself and the corresponding options are evaluated based on already loaded addOns.

gulp.task('private:app:js', function() {

  var preprocessorTask = tasks['gulp-typescript' || 'gulp-coffee' || 'gulp-babel'] || tasks.empty,
    preprocessorOptions = config.addOns['gulp-typescript' || 'gulp-coffee' || 'gulp-babel'] || null;

  return gulp.src(config.sources.appScripts)

If neither coffee, babel nor typescript is defined, gulp-empty will be invoded.

Transpiling CSS

Let's do the same for CSS. Should be a no-brainer right now. See private:app:css below

gulp.task('private:app:css', function() {  
  var preprocessorTask = tasks['gulp-less' || 'gulp-sass'] || tasks.empty,
  preprocessorOptions = config.addOns['gulp-less' || 'gulp-sass'] || null;

  return gulp.src(config.sources.appStyles)

That's all for xplatform-build let's see how our actual project has to be updated.

Refactoring our x-note project

Now it's time to update x-note. First I've replaced src/styles/app.css by src/styles/app.less and added some simple less code (copied form their website :D)

@base: #f938ab;

.box-shadow(@style, @c) when (iscolor(@c)) {
  -webkit-box-shadow: @style @c;
  box-shadow:         @style @c;
.box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
  .box-shadow(@style, rgba(0, 0, 0, @alpha));
.box {
  color: saturate(@base, 5%);
  border-color: lighten(@base, 30%);
  div { .box-shadow(0 0 5px, 30%) }

Having some less sources, I as a developer want to add gulp-less to my project by executing npm i gulp-less --D

Finally we've to specify how xplatform-build should handle our stylesheet. See the updated gulpfile.js from x-note.

    'use strict';
    var userConfig = {
        addOns: {
            "gulp-less" : {}
        sources: {
            appStyles : ['src/styles/**.less']



Updating xplatform-build

Either you can pull the recent version of xplatform-build from npm using npm install xplatform-build --D or you can update the it from your disk - if you've made all the changes to your working copy by using npm install ../path-to-local-xplatform-build

Give it a try and execute gulp build once you've saved all the files. If you've followed all the steps, you'll find the following content in dist/styles/app.min.css

.box{color:#fe33ac;border-color:#fdcdea}.box div{-webkit-box-shadow:0 0 5px rgba(0,0,0,.3);box-shadow:0 0 5px rgba(0,0,0,.3)}

So our less got transpiled as expected :)

Checkout the repos

See master branch of xplatform-build here and the BaaS branch of x-note over here


comments powered by Disqus