Friday, April 19, 2013

Kick Ass Cross-Platform Workflow With Grunt

My apologies for the vulgar title, but Grunt has me pretty excited these Days.  I work on a Mac at home and on a Windows machine at work, this means that cross platform tools are extremely important to my workflow. I hate having to use CodeKit at home and Scout at work to compile my .scss files.  Additionally tying a project to a platform specific tool means that its that much harder for others to get involved. Lately I've become a bit of a GruntJS fanboy, not only does it
meet my cross platform needs, but it cuts down the number of tools I need to use because it does so many things.
The watch plugin has made my workflow even better by allowing me to run Grunt tasks when files in my project are added, changed, or deleted. With watch whenever a .less or .scss file gets updated Grunt will see the change and automatically compile the file for me.  This post will walk you through installing watch and a compiler plugin and addresses a few of the gotcha's I ran into along the way. 

Install Grunt

Duh. Installing Grunt is out of the scope of this post but  the Grunt Homepage does an excellent job of walking you through the intstall (here's a hint you'll need to install Node too).  It's important to note here that version 0.4.0 and newer of Grunt works much differently than prior versions, and that the examples in this post will only work with version 0.4.0 or newer of Grunt.

Install Compiler Plugin

Once you have Grunt installed the next step is to get a compiler installed (since my current project is using Twitter Bootstrap I'm going to walk through setting up the LESS compiler in this post, however the process is the same for any other compiler).
To find the plugin you need the Grunt plugin page has a list of plugin's available for Grunt.  Clicking on a plugin will send you to the plugin's NPM page where you'll find documentation on the plugin and the command needed to install the plugin.

A quick not on plugins.  There are two type's of plugins "contrib" and "non-contrib".  The "contrib" plugins are official plugins and are maintained by the Grunt team.  I always prefer to use the "contrib" plugins whenever I can since they are generally better maintained and supported.
To install the Grunt LESS plugin:
  • open the terminal and navigate to the project's root directory in a terminal
  • type in npm install grunt-contrib-less --save-dev in the command line
  • hit enter
It really is that simple. The --save-dev command will ensure that the plugin, and its version, are added to your package.json file.
If you are not using a package.json file I strongly suggest you start. Using a package.json file means that you don't have to add your node_modules code to your distributions, users simply have to type in npm install in a terminal to install the dependencies.

Install The Watch Plugin

The next step is simple, install the watch plugin.  While still in your project's root directory in the terminal type in:
npm install grunt-contrib-watch --save-dev

Configure your Gruntfile

Before you go any further read the "Configuring Tasks" section of the Grunt website. This will save you a lot of time in the long run, I promise. Many plugins will assume that you know how to configure tasks and will leave these details out of their documentation.
A few points of frustration that I've run into that are covered in "Configuring Tasks" are:
  • Specifying the task name to configure. Typically the task name is the same as your plugin name.
  • Specifying source and destination files.  This is almost always left out of documentation and is almost always extremely important since a lot of plugins deal with manipulating files. 
  • Targets and how to use them (some plugins require targets and some do not, the bad news is that it's usually poorly documented whether a plugin uses them or not).
Configure the Compiler
Now that I've gotten that out of the way, lets walk through setting up the LESS compiler in the Gruntfile. In order to add a LESS task to the Gruntfile add a property named less to the object that is passed into the grunt.initConfig() function.  Since the LESS plugin requires targets (it will fail without them) I am going to specify a development target in the configuration.
A quick note on targets: if no target is specified when register or running a task ALL targets for a task will be executed.
The development target in this example only uses properties: src and dest. These properties are used to tell the LESS task where to find the .less files and where to put the compiled .css file. The syntax /**.*.less tells Grunt to get all files with a .less extension in the less directory and all of its sub-directories.

grunt.initConfig({

    less: {

        development : {

            src : [ 'less/**/*.less' ],

            dest : 'css/compiled-better.css'

        }

    }

)};

Configure Watch
The watch plugin does exactly what it's name implies, watches a directory for changes.  Since this plugin does not require the use of targets I'll skip them in this example and will put properties directly under the watch task. At a minimum watch needs two properties: files and tasks. The files property tells watch what files to look for changes for, and tasks property tells watch what tasks to run when a change is detected.
The example below is telling watch to listen for any changes to files with a.less extension in the less folder and any of its sub-folders and to run the less task when a change is detected.
watch: {

    files : [ 'less/**/*.less' ],

    tasks : [ 'less' ]

}
Register Tasks
The last step in configuring your Gruntfile is to register the less and watch tasks. To do this the following lines are added to the Gruntfile immediately after the grunt.initConfig() call:


grunt.initConfig({
    ...
});

grunt.loadNpmTasks('grunt-contrib-less');

grunt.loadNpmTasks('grunt-contrib-watch');

Run the Watch Task

The last step is to run the watch task. In a terminal window once again navigate to the root directory of the project and enter:
grunt watch
Grunt will run the watch task which will then tell you that its "Waiting...".  When a change is detected Grunt will spring into action and you'll see the normal Grunt messages start to appear in the console. When the tasks are complete watch will go back to the Waiting... status.



Monday, April 15, 2013

A Quick Look at e.target and e.currentTarget. And Bubbling.

Since jQuery makes such easy work of event listeners it's sometimes easy to ignore some of the finer points of JavaScripts events.  Two things that I often forget is the difference between the e.target and e.currentTarget properties of the event object that gets passed into a event callback. Hopefully writing this post will help the concepts stick in my head.

The reason we need both of these properties is because of event bubbling.  Event bubbling is when a event travels up the DOM, until it reaches the document node.   Lets say we have a DOM tree that looks like this:

document
|
|--div
|  |
|  |--span
|  |  |
|  |  |--a

Here we have a document node with a child of a div with a child of a span with a child of an anchor.  When the anchor is clicked the any event listeners for the anchor are triggered, then the event bubbles up to it's parent, the span and any of it's event listeners are triggered, then the event bubbles up to the div where its event listeners are triggered, and finally the event bubbles up to the document element where any  of it's event listeners are triggered.

Assuming that the span and div have a margin, padding, and border of 0 whenever a user clicks on the link the event the target property of the event that is triggered on the anchorspan,  div  and document will always be the anchor, since this is where the event originated. The currentTarget property will always be the element that is listening for the event.

The following code shows event listeners on 4 different objects, however when a user clicks on the anchor link the target will be the same for each event listener.



Open up your console and run the following example, paying close attention to the order the events fire as they bubble up the dom:

JS Bin

Wednesday, March 13, 2013

Exploring jQuery Queues

This week I ran into an interesting issue at work. There was an event that was triggered when a custom font loaded that added a fixed position element to an item in a container. Another team wrote some code that caused that container to animate when the page loaded. Sometimes the fixed position element would get placed randomly inside that container because the event was firing before the animation completed. Instead of tightly coupling the animation with the positioning of the element I decided to inspect the animating element's FX queue when the event was triggered to make sure that the element was not in the process of moving when it was added.
Queues in jQuery are a useful way to add a list functions to an element that should be executed in a particular order. The real benefit is that queues give you full control of when each item in the queue is invoked using the dequeue method. If you've used a jQuery animation function you've already used the jQuery fx queue. What a lot of people don't know is that jQuery provides a nice API for inspecting and manipulating queues.

Lets take a look at the typical use case for a jQuery queue; adding multiple animations to an element:



Demo:

JS Bin


When this code is executed each function is invoked one immediately right after the other. However, each animation is NOT performed instantly, each animation is added to the elements fx queue. When each animation is finished the next animation in the queue is invoked.

One interesting thing to note about the fx queue is that calling the stop() method on an element that is animating will only stop the current animation in the queue and immediately call the next animation in the queue. In order to truly stop all of the the animations the element's queue must be cleared as well.
In order to modify the first example to stop all animations when an element is clicked the following code is needed:



Demo:

JS Bin

Delaying And Creating Queues

Custom queues can be created on any elements by passing in a name to the queue call. In addition any queue's execution can be delayed when it is dequeued by using the delay( delayMs, queueName ) method. It's important to note that the delays are added to the queue itself so they need to be added to the queue before the function that you want delayed, however calling dequeue will trigger the delay and invoke the next callback from the queue. This timer will not start until dequeue() is called on the element's queue.

In the following example the queue's execution will be delayed by 1 second, an item will be added to the element, the queue will be delayed by another half second, another item will be appended to the element, the queue is then delayed for another second, and finally another item will be added to the element. The first item in the queue will be invoked in the $.ready() function and each callback in the queue will dequeue the next item in the queue.



Demo:

JS Bin

What makes custom queues with delays an attractive alternative to setTimeout or setInterval is that each item in the queue can have a different delay time before it is invoked.

Wednesday, February 27, 2013

Playing with ECMAScript.Harmony Modules using Traceur

As aI was a preparing a presentation on AMD and RequireJS I started looking ahead at the modules proposed for ECMAScript.Harmony.  In Addy Osmani's article Writing Modular JavaScript With AMD, CommonJS & ES Harmony he mentioned called Traceur which is a JavaScript compiler for ECMAScript Harmony syntax. This allows developers to give the future of JavaScript a test drive today.

One of the new features coming in Harmony that has me excited is modules. Modules will be a way to encapsulate code and explicitly define its dependencies and public API. ES Harmony gives us three new keywords for modules: module, import, and export. The module keyword is used to initialize a new module, the import keyword declares dependencies to import from a module into a context, and the export keyword explicitly declares public properties that will be available for other modules to import.

In addition Harmony modules:
  • are statically scoped
  • have the this keyword bound to the global object

Traceur

Before we are able to write modules today we'll need an environment that supports Harmony syntax. For this we'll use Google's Traceur compiler. In order to implement Traceur you'll need three things:
  1. Traceur library file
  2. Traceur bootstrap file
  3. Harmony code
Adding the Traceur library and bootstrap to an application is as easy as adding the scripts to a web page:



Now that we have a compiler in place we just need some code for it to compile. To do this simply create a script block with a type of script/traceur.



When the page loads Traceur will compile your Harmony code to JavaScript that works in today's modern browsers.

For your convince I've created a JS Bin with Traceur ready to go on JS Bin. In addition there is an online compiler you can use here: http://traceur-compiler.googlecode.com/git/demo/repl.html

Now that we have an environment that supports Harmony to work in lets take a look at modules.

Playing With Modules


First I'd like to point modules aren't meant to be classes, there the class keyword for that. According to the ECMAScript Wiki modules are a
"Standardized mechanism for creating libraries"
Modules do not create a new execution context, the this keyword in a module is bound to the global object. Looking at the code that Traceur outputs for a simple module definition shows this:



Even though a module does not get a new execution context , it does get a new static scope. In the following code I am creating a new module called carFactory that exports a variable named ford into the global namespace. Calling ford.wheels results in '4' and trying to access carFactory's internal wheels variable results in an error:

JS Bin

Its also important to note that doing an import * will import the variables from the modules with the same names the have in the module.

A module can also have multiple exports as shown in the following code (note the syntax for importing multiple exports in a single statement):

JS Bin

A module also doesn't only have to export objects, it can export anything:

JS Bin

Variables that are imported can also renamed the from modules using the following syntax:

JS Bin

Lastly modules can be nexted. Nested modules have privileged access to their parent modules scope. Nested modules are also private to their parent modules scope unless they are explicitly exported. Here is an example of a public nested module that accesses its parents scope:

JS Bin

Conclusion

Modules in Harmony look like they are going to be very useful and there's a lot you can do with them.  They help reduce the need for the overuse of the function keyword and reduce the need for patterns like AMD and complex loaders RequireJS and CurlJS (of which I am currently a huge fan).   For more reading on modules I suggest checking out the modules section on the ECMAScript Harmony WIKI.

Wednesday, October 24, 2012

jsonmé: A Simple HTML and JavaScript Resume Generator

It's been forever since I updated my resumé so I decided to turn my GitHub page into my living resumé.  Being a web developer I wanted to so something unique yet simple.  After playing around with a few concepts I decided to put all of my resume's data into a JSON file and create a small web app that would read it via AJAX and display its contents.  I was so happy with the result that I decided to extract out the code and put it up on GitHub and the result is jsonmé.

I wanted jsonmé to have a small footprint yet work in all browsers back to IE6.  I decided to use the Sizzle.js selector engine since it has such a proven track record in jQuery.  I also needed a small library for doing normalized AJAX requests.  I settled on snack.js, its a small and well written utility library with AJAX capabilities that also gives me a normalized document ready function.  

The resulting application is a simple and easy to implement application.  The easiest way to create your jsonmé is to fork the GitHub repository and rename it to .github.com.  For instance my personal resume is at http://bittersweetryan.github.com.  

The code is completely Open Source and licensed under the MIT license so feel free to grab it and do whatever you want with it.  If you do something awesome with it I'd love to hear about it or even get a pull request for it.

The source can be found at: https://github.com/bittersweetryan/jsonme
Fork me on GitHub