Posted on
website programming grunt jekyll

This website is powered by jekyll, an excellent static website generator. While I like jekyll quite a bit, I found my workflow for generating and minifying the stylesheets quite suboptimal. So far I used a Rakefile for automating these tasks, which I recently replaced in favor of Grunt. This blog post describes my setup.

NPM and Bower

First we need to install npm. On Mac OS X I achieved this by typing homebrew install npm. NPM allows us to install the required packages without much trouble. Add the following lines to a package.json file:

package.json
{
  "name": "mywebsite",
  "version": "0.0.1",
  "dependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-less": "*",
    "grunt-contrib-uglify": "*",
    "grunt-contrib-copy": "*",
    "bower": "*",
    "grunt-exec": "*"
  },
  "engines": {
    "npm": "1.2.x"
  }

Afterwards install the packages by running npm install, this should download all the required files to a folder node_modules.

After installing the required binaries, we need to specify which CSS and JS libraries we are using. My website makes use of jQuery and Bootstrap. Instead of manually installing these dependencies, I use Bower to install them. This can be achieved by adding the following bower.json file to the project directory.

bower.json
{
  "name": "mywebsite",
  "dependencies": {
    "bootstrap": "~3.0.0",
    "jquery": "~2.0.3"
  },
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components"
  ]
}

Running bower install then installs the two packages to the folder components.

Grunt

Similarly to a Makefile or Rakefile, Grunt allows us to define a couple of tasks and run them from the shell. In Grunt the tasks are defined in a Gruntfile.js, mine looks as follows.

Gruntfile.js
module.exports = function(grunt) {

grunt.initConfig({
  less: {
    production: {
      options: {
        paths: ["bower_components/bootstrap/less"],
        yuicompress: true
      },
      files: {
        "assets/css/application.min.css": "assets/_less/application.less"
      }
    }
  },
  uglify: {
    jquery: {
      files: {
        'assets/js/jquery.min.js': 'bower_components/jquery/jquery.js'
      }
    },
    bootstrap: {
      files: {
        'assets/js/bootstrap.min.js': ['bower_components/bootstrap/js/bootstrap-collapse.js',
                                       'bower_components/bootstrap/js/bootstrap-scrollspy.js',
                                       'bower_components/bootstrap/js/bootstrap-button.js',
                                       'bower_components/bootstrap/js/bootstrap-affix.js']
      }
    }
  },
  copy: {
    bootstrap: {
      files: [
        {expand: true, cwd: 'bower_components/bootstrap/img/', src: ['**'], dest: 'assets/img/'}
      ]
    }
  },
  exec: {
    build: {
      cmd: 'jekyll build'
    },
    serve: {
      cmd: 'jekyll serve --watch'
    },
    deploy: {
      cmd: 'rsync --progress -a --delete -e "ssh -q" _site/ myuser@host:mydir/'
    }
  }
});

grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-exec');

grunt.registerTask('default', [ 'less', 'uglify', 'copy', 'exec:build' ]);
grunt.registerTask('deploy', [ 'default', 'exec:deploy' ]);

};

Running grunt on the commandline will now perform the following tasks:

  • Compile a less file in assets/_less/application.less that makes use of the bootstrap less files and finally minify&copy it to assets/css/application.min.css.
  • Copy the jquery sources and minify them to assets/js/jquery.min.js.
  • Concatenate and minify some bootstrap javascript files and output them to assets/js/bootstrap.min.js
  • Copy the bootstrap glyph icons to assets/img.
  • A exec:build and exec:serve task that can be used for generating the website and hosting it locally.
  • A exec:deploy task that copies your website to a remote server using rsync over ssh.





comments powered by Disqus