as a better Grunt?

Automate your What is the front-end development workflow ? fully!
Jacek Tomaszewski

Front-end development Workflow(by @kristories)


  • Download
  • Scaffold


  • Watch
  • Lint
  • Compile
  • Test
  • Livereload


  • Compile
  • Test
  • Concat
  • Minify
  • Deploy

A little bit of history

of front-end development workflow


Setup phase = download & scaffold ...

  <link type="text/css" rel="stylesheet" href="css/ui-lightness/jquery-ui-1.8.16.custom.css" /> 
  <link type="text/css" rel="stylesheet" href="css/jquery.lightbox-0.5.css" /> 
  <link type="text/css" rel="stylesheet" href="css/main.css" />
  <script type="text/javascript" src="js/jquery-1.6.2.min.js"></script>
  <script type="text/javascript" src="js/jquery-ui-1.8.16.custom.min.js"></script>
  <script type="text/javascript" src="js/jquery.jplayer.min.js"></script>
  <script type="text/javascript" src="js/jquery.lightbox-0.5.js"></script>
  <script type="text/javascript" src="js/jquery.cycle.all.min.js"></script>
  <script type="text/javascript" src="js/jquery.mousewheel.js"></script>
  <script type="text/javascript" src="js/jquery.jscrollpane.min.js"></script>
  <script type="text/javascript" src="js/jquery.lightbox-0.5.js"></script>
  <script type="text/javascript" src="js/main.js"></script>

In 2011, we didn't need to compile anything
Minify and concatenation? We can do it manually
Deployment? Via FTP.
Testing? Waat? It works. If not, I test it manually.

Finally, in 2012, we met these guys:



to handle project's dependencies

$ npm install -g bower

$ bower install --save jquery
$ bower install --save jquery-ui
$ bower install --save jplayer
$ bower install --save lightbox
$ bower install --save jquery.cycle
$ bower install --save jquery.mousewheel
$ bower install --save jquery.jscrollpane


to bootstrap and scaffold projects

$ npm install -g yo generator-bespoke
$ yo bespoke

[?] What is the title of your presentation? Hello World
[?] Would you like to use a pre-made theme? Yes
[?] Would you like bullet lists? Yes
   create gulpfile.js
   create .bowerrc
   create src/index.jade
   create src/scripts/main.js

I'm all done. 
Run `gulp serve` to run HTTP server on localhost:8080 and open your presentation!


to automate development

$ grunt

Running "jshint" (jshint) task
>> 47 file lint free.

Running "qunit" (qunit) task
Testing test/tiny-pubsub.html....OK
>> 4 assertions passed (23ms)

Running "clean:dist" (clean) task
Cleaning "dist"...OK

Running "concat:dist" (concat) task
File "dist/ba-tiny-pubsub.js" created.

Running "uglify:dist" (uglify) task
File "dist/ba-tiny-pubsub.min.js" created.
Compressed size: 119 bytes gzipped (185 bytes minified).

Done, without errors.

Frontend workflow today

$ yo webapp
$ bower install --save angular
$ bower install --save angular-resource

// gruntfile.js
  concat: {
    dist: {
      src: [
      dest: 'dist/js/vendor.js'

Grunt plugins allow us to:

  • minify js, css, http files
  • compile other syntaxes (coffeescript, sass, jade, stylus, etc.)
  • hint for errors
  • watch files for changes
  • run a HTTP server
  • run tests
  • add license info
  • compile HTML templates into JS
  • use sourcemaps
  • compress images
  • move/create somes files, directories, symlinks
  • deploy to server

This was fine.

But brought as to ..

... big bunch of spaghetti code.


Grunt's issues

What if we could write tasks as stream-based commands on unix?

image by: contra/gulp

Example of Unix commands

  1. Find all files in this directory
  2. Get only those with word "grunt"
  3. Delete them
$ find . | grep -l "grunt" | xargs -I {} rm -rf {}

Example of "Imaginary front-end command"

  1. Find all *.coffee files,
  2. Compile them to JS,
  3. Send through ngMinify and UglifyJS (using sourcemaps),
  4. Concat into one file,
  5. Finally save into one final file: "dist/js/main.js".
$ find src -name '*.coffee' | coffee | ng-minify | \
  uglify --sourcemaps=true | concat > dist/js/main.js


Configuration over code

  • Configure plugins separately
  • You have to define exact order of tasks
  • Tasks can be run concurrently, if you configure grunt-concurrent plugin


Code over configuration

  • Manually write your tasks, using a stream or promise
  • Gulp will take care of your tasks dependencies itself
  • Tasks are run concurrently

Gulp task example (source)

gulp.task('scripts', function() {
  return gulp.src('src/scripts/**/*.js') // <-- Read from FS
    .pipe(gulp.dest('dist/assets/js')) // <-- Write to FS
    .pipe(rename({suffix: '.min'}))
    .pipe(gulp.dest('dist/assets/js')) // <-- Write to FS

Gulp API

is just four functions

That's it!

gulp.task(name, [deps,], fn)

gulp.task("name", ["dependency-task"], function(done) {
  // do sth ...
gulp.task("build", ["compile-js", "compile-css"]);
gulp.task("default", ["build", "server", "watch"]);


gulp.src(["app/js/**/*.js", "assets/js/**/*.js"])
gulp.task("validate-js", function(){
  return gulp.src("app/js/**/*.js")


gulp.task("compile-js", function(){
  return gulp.src("app/js/**/*.js")
});, tasks)

gulp.task("watch", function(){"app/js/**/*.js", ["validate-js", "compile-js"]);

How to start?

  1. Install Node & Gulp
  2. Install some Gulp plugins
  3. Create gulpfile.js and code it

  4. Profit!
# Enter the project's directory
$ cd myapp

# Create package.json file (if nonexistent yet)
$ npm init

# Install gulp & its' plugins locally
# (and add them to package.json)
$ npm install --save-dev gulp gulp-sass gulp-coffee

# Code the gulpfile.js file (but learn Gulp's API first)
$ vim gulpfile.js

# Finally, run a gulp's task!
$ gulp build
var gulp = require("gulp");

gulp.task("build", function(){
  // TODO

gulp.task("watch", function(){
  // TODO  

gulp.task("default", ["build", "watch"]);


var paths = {
  scripts: "app/js/**/*.coffee",
  stylesheets: "app/css/**/*.sass"

gulp.task("build", ["compile-js", "compile-css"]);

gulp.task("watch", function(){, ["compile-js"]);, ["compile-css"]);


var sass = require("gulp-sass");

gulp.task("compile-css", function(){
  return gulp.src(paths.stylesheets)


var coffee = require("gulp-coffee");

gulp.task("compile-js", function(){
  return gulp.src(paths.scripts)


Live demo


So why it's better than Grunt?

As the says:

  • Speed - tasks run concurrently
  • Efficiency - no unnecessary temporary files
  • Simplicity - Gulpfile is much cleaner



Thank you!