After I set up Medium, the next thing I did was start writing code and unit tests. And I will write about unit tests in a couple of posts, but I want to jump ahead one stage, to a build system, because that was something that required workarounds almost from the beginning and turns out to be easy to set up if you know how.

Because, of course, if you’re using CoffeeScript and SCSS, you need a preprocessing stage to turn them into something that a browser is happy with. If you have a single CoffeeScript source file, then running the coffee command is not too crazy, but what if you have multiple source files? You don’t want to run coffee on each of them individually, and you don’t want to have to load each of the outputs individually into your HTML file (or at least I don’t!). The coffee command actually has a --join argument to handle this, so you can certainly work around this manually, but this is definitely getting to the stage where a C programmer would say “I would have written a short Makefile by now”.

 

In JavaScript land, though, you probably don’t want to use Make; there are various options for build tools, and the one I chose (which seems to be the most common?) is Grunt. To get started with it, you actually want to install the grunt-cli package globally instead of putting it in your package.json file:

npm install -g grunt-cli

This makes the grunt command available, but the smarts are all in the grunt package plus whatever plugins you use. Those you install via npm install --save-dev; a good place to start is

npm install --save-dev grunt grunt-contrib-coffee grunt-contrib-sass

Grunt’s configuration file isn’t in some custom language, it uses an internal JavaScript DSL for configuration. And you can configure it in CoffeeScript, too, which is of course what I did. So here’s a basic Gruntfile.coffee:

module.exports = (grunt) ->
  grunt.initConfig {
    pkg: grunt.file.readJSON('package.json')

    coffee:
      compile:
        files:
          'js/medium.js': 'coffee/*.coffee'
        options:
          join: true

    sass:
      dist:
        files:
          'css/medium.css': 'scss/medium.scss'
  }

  grunt.loadNpmTasks('grunt-contrib-coffee')
  grunt.loadNpmTasks('grunt-contrib-sass')

  grunt.registerTask('default', ['coffee', 'sass'])

Pretty self-explanatory. (I have a bunch of CoffeeScript source files but only one SCSS file; eventually I may have multiple SCSS files, but even then I should be able to use includes to get a single entry point.) And, with that in place, I just type grunt and it builds medium.js and medium.css.

Of course, it does raise the question of how all those CoffeeScript files get combined into a single JavaScript file and what to do if you want to have control over that combining; I’ll explain that in my next post. But for now, this works as long as there aren’t load-time dependencies between your CoffeeScript files, and it outputs a single JavaScript file to load from your HTML.

 

I actually prefer not to have to manually type grunt each time I want to rebuild: I like to have Grunt watch for changes and build things every time I save. To get this to work, install the grunt-contrib-watch package and add a block like this to the initConfig section of Gruntfile.coffee:

    watch:
      coffee:
        files: 'coffee/*.coffee'
        tasks: ['coffee']
        options:
          spawn: false

      sass:
        files: 'scss/*.scss'
        tasks: ['sass']
        options:
          spawn: false

Also, make sure to add grunt-contrib-watch in the loadNpmTasks section. If you do this, then you can type grunt watch in one of your shell windows and it will rebuild whenever the appropriate files change. And yeah, it’s a bit unfortunate that you have to specify the file globs twice, but only a bit; if that really bothers you, I guess save those file globs in variables? (We are, after all, writing in a real programming language here.)

 

There’s one further change that

Post Revisions:

This post has not been revised since publication.