Sunday, June 9, 2013

Development Terminal Coolness

Hello!  Inspired by a talk at KCDC about pushing yourself to the next level professionally, I've decided to start up a blog where I talk about technical things that I do that might be useful to a wider audience.  So without further ado...

My Development Setup

We use Node.js with Express to serve up our applications and we use Grunt to build our application and do all the stuff to package our app.   Minify, compile Less, uglify, run JSHint, even run our tests.  My goal is to have more immediate feedback on my coding so if I do something wrong, I get an error immediately.  So for example, say I'm coding and something I do breaks a test, I should get a warning immediately so I can be aware of my mistake and correct it.

Grunt "watch"

Grunt has a plugin called 'watch' that will get us started.  To use it, you need to include 'grunt-contrib-watch' in your package.json file and then configure it like so in your GruntFile.js:
... 
// A task that runs in the background 'watching' for changes to code.
watch: {
    css : {
        files: ['client/assets/less/*.less', 'client/assets/css/**/*.css'],
        tasks: ['css']
    },
    debug: {
        files: ['client/app/**/*', 'client/assets/**/*'],
        tasks: ['assemble']
    },
    test : {
        files : ['client/app/**/*','client/test/**/*'],
        tasks: ['jshint','jasmine', 'mochacli']
    }
},
...
Here you can see my 'watch' configuration, which is actually 3 of them for the 3 different things I want to do. 'css' watches all my less and css files and when one of them changes grunt will trigger the 'css' task. The test subtask does the same thing, this time it watches every file in the app folder as well as the test folder and then runs 3 tasks, 'jshint', 'jasmine', and 'mochacli'. Pretty cool. To run this, just type

grunt watch
Which will 'watch' all the subtasks we defined above. If we only want to watch css, you can run
grunt watch:css

Grunt Parallel

This is all well and good, but what if I want to watch the css and the tests, but also run my server to serve up my application at the same time?  watch is a task which never ends, so I can't type
grunt watch:css runapp:development
or anything like that. Since watch:css will never end, runapp:development (which starts up my express web server) will never be run.  I could open a second terminal window and do runapp:development in there, but what if I also want to run my tests in a server via "runapp:test"?  I'd have to open another window
Enter Grunt-parallel, which lets you run multiple tasks at the same time. To install
npm install grunt-parallel --save-dev
Then, load it up in your GruntFile.js
grunt.loadNpmTasks('grunt-parallel');
With that done, we'll load configure it to run our application (via the runapp:development task) and also run the watch tasks that we want.
... 
parallel : {
    development : {
        options : {
            grunt:true,
            stream:true
        },
        tasks : ['watch:test', 'watch:css','runapp:development', 'runapp:test']

    }
}
...
Here we see a "development" task, which could be named anything, with several tasks running. First, our two watch tasks, then we have our runapp:development and finally we have our runapp:test task which starts up another express instance serving up our jasmine test files! This server is on a different port to prevent conflicts.  Now if a test fails, I'll get an error in my teminal.  Sometimes the output in the test errors are not very helpful and I need to debug more.  If I need to, I can easily jump to a browser and debug the tests from there because the tests are also being served up there!

The two options spelled above, "grunt:true" and "stream:true" which means that all my sub-tasks are grunt tasks and they're all never-ending so stream the output to the console for me.

Taking it to the next level with iTerm2

If you're using a Mac and like the power of the terminal, you should definitely check out iTerm2 link.  It has a whole host of very cool features, paste history, a way to go back in time, easily customizable color profiles, mouseless selection, plus more.  But the one I want to highlight today is its ability to trigger notifications on your desktop based on some output from your terminal.  You can use growl or since its a paid app now, you can install a program called "terminal-notifier" which provides a command line interface for publishing notifications to the desktop.  To install just run (assuming you have ruby installed):
sudo gem install terminal-notifier

Then, once it's installed, open up the iterm2 Preferences -> Profiles -> Advanced -> Triggers -> Edit and add the following trigger.  For the regular expression I used: "Warning: Task ".*" failed" which Grunt uses for whenever a task fails.  For the action use "Run Command" and for parameters put in:


terminal-notifier -message "\0 click to open tests in browser" -title "Oh no!" -open http://localhost:8888/

There are many more options you can use, to check them out, visit the project homepage (link) or check out this article for more of a summary.  What the command above does is take the regex we defined earlier and place that in the "\0" sequence in the message.  The -open flag lets you kick off a browser window to wherever you'd like.  In my case, I am pointing it to my (currently running) test server so that just by clicking the link It will open up a web page to what I broke in the tests (assuming it is a test I broke and not the jshint task).

Putting it all together

I now have a very nice single-terminal-window environment where I keep my less compiled on every change, run my tests and linter on every change and get notified immediately via the terminal and also the Mac notification bar that something has gone wrong!  Pretty slick!