Wednesday, March 5, 2014

Put Some Promise in your Cakefile

Cakefiles seem like such a simple solution, until you need asynchronous code. Even in coffeescript, the "pyramid of doom" becomes hard to handle. For example, take a look at the cakefile I use to build the huginn-liquid distribution:


util = require 'util'
{exec} = require "child_process"

task 'build:src', 'Build the Liquid source', ->

  #
  # Build the intermediate js
  #
  exec 'coffee -o lib -c src', ($err, $stdout, $stderr) ->

    util.log $err if $err if $err?
    util.log $stderr if $stderr if $stderr?
    util.log $stdout if $stdout if $stdout?
    util.log 'ok' unless $stdout?

    exec 'browserify  lib/liquid.js --debug --standalone Liquid > dist/liquid.dbg.js', ($err, $stdout, $stderr) ->

      util.log $err if $err if $err?
      util.log $stderr if $stderr if $stderr?
      util.log $stdout if $stdout if $stdout?
      util.log 'ok' unless $stdout?

      exec 'browserify lib/liquid.js --standalone Liquid | uglifyjs > dist/liquid.min.js', ($err, $stdout, $stderr) ->

        util.log $err if $err if $err?
        util.log $stderr if $stderr if $stderr?
        util.log $stdout if $stdout if $stdout?
        util.log 'ok' unless $stdout?

        exec 'browserify  lib/liquid.js --standalone Liquid > dist/liquid.js', ($err, $stdout, $stderr) ->

          util.log $err if $err if $err?
          util.log $stderr if $stderr if $stderr?
          util.log $stdout if $stdout if $stdout?
          util.log 'ok' unless $stdout?



As you can see, even with CoffeeScripts async friendly syntax, the code still starts to creep off that right edge. And adding more build steps will only get worse. But with Promises, we can fix that. First, install Q:

$ sudo npm install -g q


Now we can make some changes to Cakefile that will make it easier to read. We'll use Q's nfcall method.

util = require 'util'
{exec} = require "child_process"
{nfcall} = require 'q'

task 'build:src', 'Build the Liquid source', ->

  #
  # Build the intermediate js
  #

  start = new Date().getTime()

  nfcall exec, 'coffee -o lib -c src'

  .then ->
      nfcall exec, 'browserify  lib/liquid.js --debug --standalone Liquid > dist/liquid.dbg.js'

  .then ->
      nfcall exec, 'browserify lib/liquid.js --standalone Liquid | uglifyjs > dist/liquid.min.js'

  .then ->
      nfcall exec, 'browserify  lib/liquid.js --standalone Liquid > dist/liquid.js'

  .fail ($err) ->
      util.error $err

  .done ($args) ->
      util.log $text for $text in $args when not /\s*/.test $text
      util.log "Compiled in #{new Date().getTime() - start} ms"



Wow - that IS cleaner! And as I add more steps it will stay just as easy to read.

No comments:

Post a Comment