Moving from CodeKit to Grunt Watch + LiveReload for Real-time JavaScript/LESS/SASS Compilation

Grunt Logo

Let me start by saying that I’m a big fan of CodeKit. It’s served me well for years and I continue to use it on many of my projects. With that said, I’ve found myself doing lots of Node.js development lately and have been using Grunt for various building tasks. Grunt is a task runner that has a ton of packages for doing things like compiling LESS/SASS into CSS, concatenating JavaScript, minifying, etc. It also has a package for watching files (the same way CodeKit does) and firing off certain tasks when they’re modified.

Given that Grunt has these features, once it’s integrated into a project, it makes sense to leverage it for the real-time compiling and reloading of JS/LESS/SASS files. You’ll be able to reuse many of the same build tasks and it’ll allow other developers (who may not have CodeKit installed) to easily follow the same workflow when they open your project. Here’s how to do it.


Suppose we have a project using JavaScript and LESS. The file structure looks like this:

/javascript
  /jquery.js
  /functions.js
  /app.js
/less
  /_header.less
  /_footer.less
  /_body.less
  /style.less
/public
  /css
    /style.css
  /js
    /main.min.js

We have 3 JavaScript files in the /javascript directory that need to be combined and minified into /public/js/main.min.js. We also have a style.less file (that imports the other underscored .less files) and compiles down into /public/css/style.css. Simple enough.

In CodeKit, you’d drag this whole folder into your window. You’d configure some options and set the output paths, then you’d be good to go. CodeKit would start watching the files and automatically recompile.

In Grunt, however, we need to explain these procedures via a configuration file. Don’t worry. It’s easy! Here’s what you need to do.

(Note: I know this seems like a lot of steps, but often times many of them are done already — especially if you’re working on a Node.js project)


1. Install Node.js (with NPM)

Even if your project isn’t written in Node.js, you’ll need it to access these tool. Just go to nodejs.org and grab the latest copy. This will also install NPM (the Node.js Package Manager).

2. Install Grunt

Because you’ll be using Grunt a lot, it’s easiest to just install it globally. You can do that by running this command:

sudo npm install -g grunt-cli

(After the installation is complete, you may need to exit your terminal window and reopen it again to gain access to the “grunt” command.)

3. Configure NPM’s package.json with Grunt Plugins

Ok, NPM is installed. Now we need to configure the necessary packages so that all the Grunt plugins we need will be downloaded. You’ll need to create a package.json file with the contents below. If this file already exists, just add the entries in the dependencies section.

{
  "name": "my-project-name",
  "version": "0.0.1",
  "dependencies": {
    "grunt-cli": "latest",
    "grunt-contrib-concat": "latest",
    "grunt-contrib-uglify": "latest",
    "grunt-contrib-less": "latest",
    "grunt-contrib-watch": "latest"
  }
}

4. Install Grunt Plugins via NPM

Now that we’ve configured our package.json file with the packages we need, let’s install them.

npm install

This will download all the packages we specified above and place them into the node_modules directory in your project’s root.

5. Configure Gruntfile.js

Ok, everything is installed. The last thing we need to do is setup Grunt’s configuration file.

module.exports = function(grunt) {

  grunt.registerTask('watch', [ 'watch' ]);

  grunt.initConfig({
    concat: {
      js: {
        options: {
          separator: ';'
        },
        src: [
          'javascript/*.js'
        ],
        dest: 'public/js/main.min.js'
      }, 
    },
    uglify: {
      options: {
        mangle: false
      },
      js: {
        files: {
          'public/js/main.min.js': ['public/js/main.min.js']
        }
      }
    },
    less: {
      style: {
        files: {
          "public/css/style.css": "less/style.less"
        }
      }
    },
    watch: {
      js: {
        files: ['javascript/*.js'],
        tasks: ['concat:js', 'uglify:js'],
        options: {
          livereload: true,
        }
      },
      css: {
        files: ['less/*.less'],
        tasks: ['less:style'],
        options: {
          livereload: true,
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-watch');

};

This configuration file setups up a number of tasks for concatenating, compiling and minimizing the JS and LESS. It also tells Grunt to execute the tasks anytime the files are modified.

6. Run Grunt Command to Watch Your Files

Now that everything is downloaded and configured, we simply need to run a single command to make Grunt start watching our files.

grunt watch

Run this command (in your project’s root directory) anytime you want Grunt to start watching your files. To stop the process, simply use control + c on your keyboard.


You’ll notice that there are a few livereload flags in the Grunt configuration file above. This tells Grunt to alert LiveReload that files have changed so that it can automatically refresh your browser window. For this functionality to work, you can purchase LiveReload or just install the free LiveReload Chrome Extension. (Make sure it’s enabled by clicking the icon in your browser’s toolbar.)


That’s everything you need to get started! Please note that if your files are structured or named differently, you may need to adjust the configuration above. Also note that Grunt has a huge library of plugins that do much more than what’s show here, so take a look and poke around.


Note: If enjoyed using Grunt above, check out my new article on Grunt deployment using the grunt-ssh plugin and Git.

  • Marc
    • http://justinklemm.com/ Justin Klemm

      Whoops. Yes, you’re right in thinking that. I’ve fixed the typo. Thanks for the heads up!

  • atomworks

    I’m looking to make exactly the same move so this article is awesome! One question though, do you find Grunt compiles SCSS files faster than CodeKit? I’ve got a Compass based framework for CSS and it takes a few seconds to compile which when you’re in the work flow is a little frustrating.

    • http://justinklemm.com/ Justin Klemm

      Glad you found it useful! It’s a little tough to gauge speed because I think a lot of that probably has to do with the size of your project and how much code is being compiled. In my experience, CodeKit was fast enough that the compilation process never caused me any issues. To be totally honest, I would actually say my Grunt setup is slightly slower, but again, not slow enough to hinder my development process.

      I know I’ve heard some talk about different SCSS compilers. If I recall, people were complaining that Compass made things very slow and that there were some other setups that were much faster… but that’s just anecdotal. I’ve never developed with Compass, so I can’t say.

      • atomworks

        Compass seemed a little less verbose when it comes to compiling, Grunt seems a little more detailed in it’s feedback whilst watching which is much nicer.

        I’m hoping Grunt will avoid some of the CPU spike / memory leak problems I get from time to time with CodeKit. Having LiveReload to switch on and off in individual tabs through the extension rather than using CodeKits refresh active tabs will definitely ease work flow and hopefully reduce some of the Chrome CPU rendering spikes that I’ve found coming more common with CK’s reload method.

        • http://justinklemm.com/ Justin Klemm

          Cool, yea, you’ll have to give it a shot and see. Being able to flip LiveReload on and off per tab is definitely nice. I should note that the Grunt method will not instantly inject the CSS into the page without refreshing it (the way that CodeKit can), but that’s not a deal breaker for me.

          • jude.w

            Hi, I found a post about how to fix this issue. Don’t just watch for the changes in that files source, watch the file itself. After doing this, it works great for me.
            http://draftingcode.com/2013/06/subtle-live-reloading-with-grunt-and-compass/

          • http://justinklemm.com/ Justin Klemm

            Hey, I just read the article. Interesting insight! I’ll test this out tomorrow and see if applying LiveReload to just the final CSS results in seamless injections for me. Thanks!

          • Antonio Brandao

            It worked for me ! :) bliss

          • Antonio Brandao

            brilliant !

    • http://www.wordimpress.com/ Devin Walker

      I’ve also run into slowness issues using Grunt + LiveReload. Sometimes it takes Chrome 3-4 seconds to fully reload. Other times, it just works. I’ve never tried codekit before but have heard good things about it.

      • http://justinklemm.com/ Justin Klemm

        Devin, are you seeing that slowdown just compiling LESS/SASS? Or is Grunt doing a bunch of stuff before hitting live reload (linting, minimizing, etc.)? If it’s the latter, that could be an issue.

        CodeKit is very snappy. I’m a fan of using it for simple, personal projects, but it’s a pain (and costs money) to replicate your setup on other machines, so it’s not a great option for projects that involve a team or need to be built during deployment.

        • Harry Pujols

          Codekit costs money, yes, but replicating your setup in other machines is not a problem. You can choose in the preferences, or in any particular project, to save a codekit-config.json file that will keep your project setup intact in other computers. Compared to the complicated, and error-prone initial setup of Grunt, the only disadvantage of Codekit is the price and that it’s not platform agnostic.

          • http://justinklemm.com/ Justin Klemm

            Harry, I appreciate that Codekit has an export option, but what if you’re working with developers on Windows or Linux? Isn’t Codekit currently Mac-only? That means they’d need to find/setup their own configurations. Why not just specify it once in Grunt, then everyone can use it (for free)?

            Beyond that, how do you handle deployment with Codekit? If I’m working on a project that uses Coffeescript and Less, I only want to keep the .coffee and .less source files in my repo and compile them during deployment. This is easy with Grunt on any type of system. For example, with Node.js you would simply create a grunt “build” command and specify it in your package.json’s “postinstall” setting. To my knowledge, doing that type of “compilation on deployment” (which is fairly common with any medium to large size project) is not possible with Codekit.

            Again, I have nothing against Codekit. I use it on a number of small, personal project… but when multiple developers and a more complex deployment setup come into play, a better solution is needed.

          • Harry Pujols

            That’s why I said that Codekit disadvantage is that is not platform agnostic. It’s a big problem when I have to work from a computer running Windows, though Prepros covers most of the issues.

            Depending on what method you use for deployment, it’s as easy as setting a .gitignore file, or I don’t know what, but whatever it is, it will still be easier than setting up a gruntfile.

            Though Grunt can definitively do so much, setting up a Grunt project is complicated, specially for the people who is going to use it the most: Designers who are generally allergic to using the command line. I am one that after Git GUI apps became more mature, stopped using Git on the command line for everything but the rarest of cases. Sure, after you get Grunt running, it’s great, but I understand why many would prefer paying for Codekit (or Hammer, or Mixture, or Prepros), rather than trying to understand all the moving parts required to get a Grunt project set.

            Thank you for your post, though. I hope this gets more people interested in using Grunt.

          • http://www.wordimpress.com/ Devin Walker

            I agree that Grunt can be intimidating for many…

          • http://justinklemm.com/ Justin Klemm

            Yea, agree with both of you that Grunt can be intimidating. I’ve tried to simplify it above, but if you’re not super comfortable with the command line, it may take a little time to get used to it.

            I think usage of Codekit or Grunt is really dependent upon the situation and the person. If I were starting a project tomorrow that was going to have 3-4 developers coding on it, source control, and a real deployment process, I’d go with Grunt. If I was coding up a new personal website design, or working on a simple project where I know it’d just be me, I’d use CodeKit for the speed and simplicity.

            With that said, everyone should decide what makes sense for them. Good luck to both of you with whatever tools you end up using.

        • http://www.wordimpress.com/ Devin Walker

          It’s definitely faster if I only compile the LESS but still I receive a 2-3 second wait and a full browser refresh. I wish it just worked… it seems like linux/mac users have a much smoother experience.

    • Dan

      I’ve tried both CodeKit (for a LESS project) and Grunt (for several Sass/Compass/Susy projects) so here’s my 2c: Both solutions have a learning curve and would be problematic for a new developer coming on to the project with no introduction. Grunt is more powerful, but CodeKit seemed to be much faster (but then it was doing less (and LESS), because there was less that it could do). Overall I think that Grunt (or Gulp, or whatever TNBT is) is a better way to go as there is a bigger community working on plugins for it, but you will definitely need to factor in some time for troubleshooting and performance tweaking.

      • http://justinklemm.com/ Justin Klemm

        Dan, thanks for your thoughts. I agree on all these points. Overall, I’ve also found Grunt to be slower than CodeKit, but the other benefits still make it my (usual) solution of choice. I’ve heard that Gulp is much faster. I’m hoping to dig into it soon and follow up with another post.

  • Jaggli

    Thank you very much.

  • http://aussietheatre.com.au/ Matt Edwards

    Great Article, thanks Justin Klemm

    I’m a long time CodeKit user in the process of switching over the Grunt. I’m wondering if you know how to refresh on changes to a .php file??

    at the moment I have this under my watch:

    php: {
    files: ['*.php']
    },

    But it seems to get stuck in a never ending loop of refreshes?

    • http://justinklemm.com/ Justin Klemm

      Matt, that snippet would work if you have the PHP files all in the same base directory. You might want to try something like this:

      php: {
      files: ['**/*.php'],
      options: {
      livereload: true
      }
      }

      As far as the infinite reloading, I’m not really sure why that would happen. Is CodeKit setup too? Perhaps some kind of conflicting behavior?

  • Carl-Erik Kopseng

    Shameless plug: I have created a grunt plugin that will compile all your existing kit-files. It’s on GitHub, a few minutes old, but working :-)

    https://github.com/fatso83/grunt-codekit

  • Lefthandmedia

    HI, Codekit has this nifty function you can import javascripts to concatonate by importing them in the Script.js by putting @codekit prepend “myother.js” in the main.js. Is there a grunt plugin that does the same?
    I know grunt can concatonate js but i have to put all filereferences in the grunt file. I rather put all dependencies in the main.js since i have several of them.
    Is that at all possible with grunt?

    • http://justinklemm.com/ Justin Klemm

      Hi, I’m not aware of any plugins that support that functionality out of the box (though they might be out there). I came across this answer on Stack Overflow that has a suggestion (but it seems rather complicated): http://stackoverflow.com/questions/18387220/grunt-concat-use-file-instructions-a-la-codekit

      If you’re feeling ambitious, it probably wouldn’t be *that* hard to write a Grunt plugin to support those @codekit commands :) but obviously just using grunt-contrib-concat is much easier.

      Good luck with your solution!

  • Benjamin Fayle

    Does the release of CodeKit 2 change your thinking?

    • http://justinklemm.com/ Justin Klemm

      Hey Ben, I’m eager to try CodeKit 2. I haven’t had a chance yet. The Bower integration looks really nice.

      One of the biggest hurdles for me, though, is how do you use CodeKit when you have, say, 4 developers (2 on Mac, 1 on Windows, and 1 on Linux) working on a project and all the configuration needs to be committed so each can easily build/deploy the system? I really love CodeKit as an individual’s tool and still use it as such for small projects, but as you start to scale up, it becomes unsustainable (in my experience, at least). So in that sense, I’m not expecting my thinking will change — but I’m still looking forward to giving it a shot.