ponyfoo.com

Continuous Development in Node.js

Fix
A relevant ad will be displayed here soon. These ads help pay for my hosting.
Please consider disabling your ad blocker on Pony Foo. These ads help pay for my hosting.
You can support Pony Foo directly through Patreon or via PayPal.

With Grunt, the JavaScript task runner, it’s becoming increasingly easy to tackle continuous development. The goal is being able to work uninterruptedly in our code-base while developing. To this effect, there’s quite a few things you could do.

  • Replace node with nodemon (for development), which restarts the node process whenever relevant files change
  • Use the watch task in Grunt to re-execute relevant tasks when files change
  • You should invest in a text editor that saves files for you!
  • Using livereload, so that you don’t even have to refresh the browser

How the hell do we make sense of all of that, and combine them in such a way that they don’t collide into each other and die? Well, read on.

grunt.png
grunt.png

Nobody has time for a full grunt build every 2s

Does grunt build automates your builds? Awesome! Who automates grunt build? grunt watch will! If you’re like me, you hit save, or change tabs every few seconds. You can’t afford to run a full build every time you change a comment or a comma, because that’d be a tremendous waste of your time. Yet, a lot of people do this, because they haven’t found a better way to go about it yet. You’re reading this, so you’re one foot ahead. Kudos. Let’s start off by installing grunt-watch.

npm install grunt-contrib-watch --save-dev

If you haven’t already, also install load-grunt-tasks. Then replace all your grunt.loadNpmTasks calls with:

require('load-grunt-tasks')(grunt);

That will save you some time in the long run. Now, grunt-contrib-watch is fairly easy to set up. Here’s a sample:

{
  "watch": {
    "rebuild": {
      "tasks": [
        "build:rebuild"
      ],
      "files": [
        "Gruntfile.js",
        "build/**/*.js"
      ]
    },
    "jshint_client": {
      "tasks": [
        "jshint:client"
      ],
      "files": [
        "src/client/js/**/*.js"
      ]
    },
    "jshint_server": {
      "tasks": [
        "jshint:server"
      ],
      "files": [
        "src/srv/**/*.js",
        "app.js"
      ]
    },
    "css": {
      "tasks": [
        "css:debug"
      ],
      "files": [
        "src/client/css/**/*.styl"
      ]
    }
  }
}

This will run jshint on my client-side code when it changes, on the server-side code when that changes, it will run the css:debug task whenever one of my Stylus stylesheets changes, and it will run the entire build process if it itself changes. The list of tasks goes on, but I didn’t want to cloud you with lists of tasks and files, you get the idea.

Watch only for the files that directly affect a build task, and run that particular task (or set of tasks) when one or more of those files change. Repeat this for every build task you perform.

This helps you to avoid running the build process by yourself whenever something changes, and at the same time it’ll be way faster, because only the necessary tasks will run at each point. Remember to clean up before running tasks, using grunt-contrib-clean.

Now all you need to do is set up a dev alias or similar, and make it look like this:

grunt.registerTask('dev', ['build:debug', 'watch']);

Awesome, you’re halfway there.

Ain’t nobody got time fo’ dat! ctrlc,,

aint-nobody-got-time.jpg
aint-nobody-got-time.jpg

That’s the sequence of keys you often find yourself typing when you’re not using nodemon, and you should be embarrased. We won’t be using nodemon directly, because that’s too cumbersome. Instead, we want to integrate it with the bunch of watch task targets we’re using. The problem is, both grunt-contrib-watch and grunt-nodemon are blocking. Meaning: these tasks are never supposed to end. That represents a problem when attempting to run them serially, like Grunt is used to do. We want them to run side-by-side, like the best friends in the world they are. Enter grunt-concurrent. grunt-concurrent solves that problem by spawning new processes for each task it’s required to run. Something like this will do the trick, parallelizing watch and nodemon:

concurrent: {
  dev: {
    options: {
      logConcurrentOutput: true
    },
    tasks: ['watch', 'nodemon:dev']
  }
}

That’ll do it. but how should we configure the nodemon task? Glad you asked.

nodemon: {
  dev: {
    options: {
      file: 'app.js'
    }
  }
}

There’s a little thing, too. nodemon is kind of silly, in that it watches for almost everything. Well, it defaults to .js, and .coffee files, but that includes stuff in node_modules, too. If we use a .nodemonignore file, such as the one below, we can ignore stuff that doesn’t really affect node itself.

# seriously? ignore git changes
./.git/*

# package control
./node_modules/*
./bower_components/*

# logs
./npm_debug.log

# build artifacts
./bin/*

# deployment artifacts
./deploy/*

# os artifacts
.DS_Store

# ignore client-side js
./src/client/*

# ignore tests
./test/*

Oh, and remember to update your dev alias, too.

grunt.registerTask('dev', ['build:debug', 'concurrent:dev']);

Done! Next!

Automate all the things! Drop ctrls forever

automate-all-the-things.jpg
automate-all-the-things.jpg

Simple, use a text editor that is dilligent enough that it’ll do the saving for you. End the ctrls non-sense!

  • Using WebStorm? You’re golden!
  • vim is your peanut butter? then you could use this link.
  • Sublime Text and its many cursors make you the happiest assembly line worker? Here you go!
  • Your text editor doesn’t auto-save? Ditch it!

It will feel kind of weird at first, but as you get used to it, you’ll fall in love and never look back.

Refreshing the browser by hand? No way! Forget ctrlr

Almost! Okay, we’ve now fully automated everything. Pretty much. We could throw-in livereload, since it’s even bundled together in grunt-contrib-watch now. First and foremost, install the browser extension for livereload.

Then, it’s just a matter of adding a target to the watch task.

watch: {
  livereload: {
    options: {
      livereload: true
    },
    files: [
      'public/**/*.{css,js}',
      'views/**/*.html'
    ]
  }
}

No more F5? Sign me up!

Unbox it

unbox-256.png
unbox-256.png

I iterate over my build processes a lot, and now I finally put it together in a project that’s ready to clone and work on. I didn’t want to spend a bunch of time copying and pasting every time, and I figured it’d be useful to you too. Without further ado, I present unbox to you. Clone using the command below:

git clone https://github.com/bevacqua/unbox my-repo
cd my-repo
cat unbox.sh | sh

Doing that will:

  • git clone the latest version of unbox
  • Remove the .git folder to avoid confusion
  • npm install
  • bower install
  • Profit!

It doesn’t just provide a build process, but an opinionated way to lay out the architecture, build process, and folder structure of any new application you want to develop with Node.

Let me know if you find this kind of module to be useful, I sure do!

Updated grunt-ec2!

By the way, I’ve updated grunt-ec2, introduced in this post if you haven’t read that yet, and it now has more features!

  • Port forwarding
  • nginx! This one made me a really happy pony
  • Proper configuration, setting NODE_ENV to the name tag we’re using
  • Hard reboots of the EC2 instance, pm2, or nginx
  • Fine grained control over your deployed application without having to ssh into the EC2 instance by yourself

You can look at the complete change log on GitHub.

Oh, I didn’t see you there! You see, I’m writing a book on this kind of things. If build processes, application architecture, and JavaScript are things that warm your noodles, then stay tuned for updates about my book!

Liked the article? Subscribe below to get an email when new articles come out! Also, follow @ponyfoo on Twitter and @ponyfoo on Facebook.
One-click unsubscribe, anytime. Learn more.

Comments (3)

Tony Brown wrote

Great article, I’m going to install your repo now and learn how to use it, I don’t use Grunt, but it seems like it’s worth the time to learn how to use it. Thanks for the info

Kevin Hill wrote

What a fantastic article, you have saved me so many keystokes! alt + tab is all I need now to just work, work, work away