If you’re in the know then you’ve probably already heard about the Node task runner Grunt. If you are like me and didn’t have time to try it out then FIND THE TIME! Grunt has improved my workflow, enforced higher code quality and saved me time!
- can run in the background (watch)
- is very fast (compiles my SASS/CSS, lint and compress my JS in < 1.5 seconds)
- works with everything through plugins (I love online communities!)
- easy to configure… once you understand it a bit
I wouldn’t be writing a blog post if I didn’t think I had something to contribute. The catch with grunt is that there is a small learning curve and it can take a while to find the right kind of compilation combination that you want.
I owe my grunt learning to these 2 resources:
They are good and easy reads and will get you on the right track. I will try and cover the bits they were missing below.
The Gruntfile.js config
My workflow may be similar or useful for you so I’ll simply share my process.
- I run “grunt” (which runs “grunt watch“) to kick things off for development.
It then starts off “grunt dev” which includes “grunt devCSS” and “grunt devJS” which overwrites any old files I may have had.
- Every time I save a file the above JS and CSS dev based tasks are fired.
The devJS task:
- JsHint files (more friendly than JsLint)
This stops the grunt task if the linter reports an issue (which is wonderful!)
- concatenates files (in a set order)
- and outputs a compressed version
I end up with the following files in js-build/ site.js, site.min.js, site.min.js.gz. The gzipped version is sent if the appropriate “accept compression” browser header is sent. If not then the site.min.js version is sent.
The devCSS task:
- calls compass with various options to run SASS and output CSS files (with comments in dev mode)
- compresses output files
I end up with build-site.css and build-site.css.gz. As with JS, the appropriate file is sent on demand.
I have a single CSS file included in my head tag and a single JS file included before my closing body tag. Various lazy loading optimisations can be included but it wasn’t needed for this particular workflow.
To consolidate what you’re read above, here is the actual Gruntfile.
Note that I am using the files array syntax because it allows for multiple sets of files to be processed through the same task. For simplicity I have removed the additional JS builds.
I run “grunt prod” which runs “grunt prodJS” and surprisingly “grunt prodCSS“. The only difference is that the JS is also “uglified” before being compressed and the compass/SASS options are without comments and compiled to a compressed format (no white space etc.). This is lighting fast for me considering a good sized JS and CSS collection.
If you want to improve this workflow then one could simply skip the compression task for files in the “grunt dev” process and make sure the .gz files are removed to force the non-compressed version (the fallback) to be sent by Apache. Compression is generally the part that takes the longest so it may be worthwhile for bigger projects. I didn’t bother because everything runs so fast anyway and it makes for one less difference between production and development setups. I also would have to add another task (node dependency) for deleting the gz files.
There are some limitations with various tools at the time of writing this post which are yet to be patched in official releases. You may run into problems of ‘globbing’ for the input source files and exporting files with the correct name and suffix due to the underlying file system wrappers (node-globule) used in grunt.