Articles

Becoming Self-Sufficient With Grunt

I’ve fallen in love with Grunt, the so-called JavaScript task runner. Before I go into the namesake of this post, I want to first talk about what Grunt is and why you should be using it.

Although the “JavaScript taskrunner” is, in a very mechanical sense, true, it does nothing to tell you what Grunt will do for you as a developer. Grunt makes it really easy to whip your static files into shape. If you use any sort of preprocessors, you know you ultimately have to get the files you author into something the browser can understand. SASS and LESS have to come back around to CSS, HAML needs to be HTML, CoffeeScript will end the day as JavaScript, etcetera.

CodeKit does a good job of this for Mac users, but it’s maintained by one man (so far as I know) which limits the featureset to what that one man can turn out. He’s done a great job, but he can’t compete with the entire Grunt community turning out plugins for everything under the sun. Windows users have options, but I’ve heard of nothing that seems to approach CodeKit. Grunt can do all these things and then some.

That’s generally what Grunt can do for a developer. Now, here’s how I use Grunt. I’ve created two tasks: a default task and a build task. The default task is a magical task which runs whenever you type grunt at the terminal. In this task, I’ve included plugins useful for my development workflow. My thinking is that I’ll be developing more than deploying, so development-specific workflow gets the shorter command. The build task gets run when I type grunt build. You can have any number of tasks named anything you like and run them with grunt <taskname>.

In the default task, I

  • Run jshint on my scripts
  • Concatenate the scripts (Not necessary in many development scenarios, but it’s what I needed for this particular project.)
  • Run Compass to compile my SASS with the development options (preserving comments and nesting)
  • Start a development server
  • Start watching for changes in my JS and SASS

All these tasks are performed by Grunt plugins with very minimal configuration. My build task is slightly different.

  • Run jshint as in the default task
  • Concatenate and uglify scripts
  • Run Compass in production mode (remove comments, concatenate, and minify)
  • Compress images using Yahoo’s Smush.it lossless JPEG/PNG compression tool

You’ll notice here I’m not running the dev server or the watch task. That’s because the assumption here is that development time is over, and it’s time to get down to business. These files are ready to deploy.

My setup is a simple one, but it provides me with a great deal of convenience. Grunt is a command line tool with all that entails, but, as is often the case with the command line, the power and flexibility cannot be matched by anything with a GUI.

All this sounds good, but how do you get started using it? I’m going to walk with you down the same path I took to Gruntland. It’s not even that treacherous!

First, you need to read the Grunt Getting started page. This will help you get Grunt installed and show you around a bit. Then, you need to look at their Configuring tasks page — in particular, the Files section of it. Almost every Grunt plugin operates on your files in some way. This section shows you how to tell the plugin which files to watch and where to put any output files it might have. Grunt offers a few different formats for this.

For simple configurations, the compact format works really well. If you have something a bit more complex and need to change settings per file location, you might want to look at the files array format. You can mix and match inside your Gruntfile, so just keep them in mind. It’s good to have a couple of them in your repertoire.

Next, check out this great primer by Sethen Maleno. He does an excellent job of easing you into Grunt. Now, you should have a nice working setup. I hope, at this point, you’re a little dizzy thinking of all the other things you might be able to have Grunt do, but maybe you’re not sure quite how to get there.

Before we get started, here’s my Gruntfile. Don’t worry about trying to figure out what everything does, but you may want to refer back to it as I talk about its parts to get a bird’s-eye view.

var scripts = ['js/jquery-1.9.1.js', 'js/jquery.animate-enhanced.min.js','jquery.easing.min.js', 'js/**/*.js', '!js/scripts.js'];
  module.exports = function (grunt) {
    // Project configuration.
    grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),
      jshint: {
        options: {
          force: true
        },
        all: scripts + ['!js/jquery-1.9.1.js', '!js/jquery.animate-enhanced.min.js', '!jquery.easing.min.js']
      },
      concat: {
          dist: {
            src: scripts, dest: 'js/scripts.js'
            }
          },
      uglify: {
        min: {
          files: {
            'js/scripts.js': ['js/scripts.js']
          }
        }
      },
      compass: {
        dev: {
          options: {
            sassDir: 'sass', cssDir: 'css'
          }
        },
        production: {
          options: {
            sassDir: 'sass', cssDir: 'css',
            environment: 'production',
            outputStyle: 'compressed',
            force: true
          }
        }
      },
      smushit: {
          images: {
              src: ['img/**/*.{png,jpg,jpeg}']
              }
            },
          watch: {
              options: {
                  livereload: true
                },
                scripts: {
                    files: scripts, tasks: ['jshint', 'concat']
                },
                styles: {
                    files: ['sass/**/*.{sass,scss}'],
                    tasks: ['compass:dev']
                }
            },
            connect: {
                server: {
                    options: {
                        port: 8888,
                        hostname: '*'
                    }
                }
            }
        });
        grunt.loadNpmTasks('grunt-contrib-jshint');
        grunt.loadNpmTasks('grunt-contrib-concat');
        grunt.loadNpmTasks('grunt-contrib-uglify');
        grunt.loadNpmTasks('grunt-contrib-compass');
        grunt.loadNpmTasks('grunt-contrib-watch');
        grunt.loadNpmTasks('grunt-contrib-connect');
        grunt.loadNpmTasks('grunt-smushit');
        // Development task checks and concatenates JS, compiles SASS preserving comments and nesting, runs dev server, and starts watch
        grunt.registerTask('default', ['jshint','concat', 'compass:dev', 'connect:server', 'watch']);
        // Build task builds minified versions of static files
        grunt.registerTask('build', ['jshint', 'compass:production', 'concat', 'uglify', 'smushit']);  };

Let’s learn how to become self-sufficient with Grunt. What’s the point of having access to all these great plugins if you don’t know how to set them up? Thankfully, most of the plugins do a great job of documenting how they work. You probably have an idea of what you want Grunt to do, but you’re not sure if a plugin is available. Your first stop is the official Plugins page.

I know my site has several images that could probably be compressed better, and, although I love ImageOptim, it’s a bit of a pain to have to run it manually every time I add an image or make a change. I’ll start with a search for jpg.

That yields a few different options for me. Notice the first option in my results: contrib-imagemin. Plugins named with “contrib-” are developed by the Grunt team. That means you can usually count on these to be stable and well-documented. I use several of the official plugins, and they are incredibly useful. However, I’m a rebel. I’ve heard of Yahoo’s Smush.it service, so I’ll try the smushit plugin instead.

Clicking takes me to the npm page for the plugin. “npm” stands for node package manager. (Update: Reddit user tribalfloyd pointed out that this is not correct. According to the documentation, “it is a recursive bacronymic abbreviation for ‘npm is not an acronym.’”) You should have installed it in a previous step. If you have, you’ll start setting up this plugin by installing it with npm. The command is right here on the npm page under “Getting Started.” Every plugin I’ve tried so far has this in the documentation, but it is also pretty constant across plugins. You first install the plugin by running npm install <package-name> --save-dev replacing <package-name> with the name of this particular npm package. That name is at the top of the npm page for the package. So, our command to install the Smush.it plugin from the terminal is npm install grunt-smushit --save-dev.

Most of what this command does is easy to decipher, but the --save-dev may not be. This switch adds the package to your package.json file, the file which tells npm about the requirements for this project (among other things). If you’re collaborating or would like to share your project, this file will allow another person to quickly get the project up-and-running on a different computer by simply running npm install in the project directory.

Now that we have the plugin installed, we’ll tell Grunt about it. This is also in the “Getting Started” section of the documentation. To do so, add grunt.loadNpmTasks('grunt-smushit'); to your Gruntfile.

This is where plugins start to diverge: task configuration. As I said before, most plugins need to be told about which files they should watch, and that’s easily accomplished with the information on Grunt’s Configuring tasks page. Everything else is up in the air. Your saving grace is the plugin documentation’s “Task” section where you learn the particulars of configuring this plugin.

The Smush.it plugin offers a quick and simple configuration right at the top. This is really nice. If you don’t have any special needs, you can look at this and quickly figure out what you need to do. It’s important to note that, for most plugins (perhaps all), the first object inside the plugin’s object is the name of your task configuration.

grunt.initConfig({
    smushit: {
        mygroup: {
            // This is the name of this configuration.
            // It's completely arbitrary, and I can make it whatever I want.
            src: ['tests/img/**/*.png','tests/img/**/*.jpg'],
            dest: 'tests/img/min'
        }
    }
});

You can make it whatever you want. This allows you to have multiple task configurations for the same plugin. Back in my Gruntfile, take a look at the Compass plugin task configuration on line 31 to see what I mean. I have a dev task and a production task each with its own set of options.

Browse through the “Task” section and see which options are available for the plugin. You can also see the default value for each of the available options. In the case of Smush.it, the only one is service which you probably won’t want to use. This lets you use a different service for image processing besides Smush.it which is kinda the point of this plugin, right?

However, if you did want to set some options, you can do it in one of two ways: you can make an options object inside the plugin’s object or you can make an options object inside one or more of your configurations for the plugin. I’m going to pull out my Compass plugin config as an example… and it’s a good thing, too, because it needs to be refactored a bit.

compass: {
    dev: {
        options: {
            sassDir: 'sass',
            cssDir: 'css'
            }
        },
    production: {
        options: {
            sassDir: 'sass',
            cssDir: 'css',
            environment: 'production',
            outputStyle: 'compressed',
            force: true
            }
        }
    }

You can see the options objects under the dev and production configurations, and I have some duplication here. The SASS and CSS directories are the same in both cases. I want to pull this out and and add it to an options object directly under the plugin’s object. Here’s the new configuration:

compass: {
    options: {
        sassDir: 'sass',
        cssDir: 'css'
    },
    dev: { },
    production: {
        options: {
            environment: 'production',
            outputStyle: 'compressed',
            force: true
        }
    }
}

Now, my config is much DRYer. The dev task no longer makes any changes to the configuration at all. If I wanted, I might explicitly set the dev task’s environment option to development, but, since that’s the default value, it’s not necessary.

You can also override your plugin-level options with task configuration level options if you need to. This might be helpful if you had several tasks under a single plugin and most use a particular setting. You could configure that option directly under the plugin but change it inside the individual task or tasks that need a different setting.

Once your configuration is done, save it and run the task with grunt <plugin>:<task>. You can omit :<task> if you only have a single task configured for the plugin. If you have several, run this for each one to make sure they all work assuming the tasks won’t destroy anything.

You’re almost there! To really get the most out of your new plugin, you’ll want to add it to one or your custom tasks. Smush.it is going into my build task. I don’t really care about optimizing images for my local development, but I need them to be lean and mean on the web. Here’s that task before Smush.it:

grunt.registerTask('build', ['jshint', 'compass:production', 'concat', 'uglify']);

and after:

grunt.registerTask('build', ['jshint', 'compass:production', 'concat', 'uglify', 'smushit']);

This part is really simple. Just add the name of your task to the task’s array. If you had multiple configurations, follow the plugin name with a colon and the name of the task you want to run. You can see that in action with the Compass task in the configuration above.

The only caveat is that you need to consider the order of the tasks. In this case, it doesn’t really matter when the images are optimized relative to the other tasks. However, if you look at the two tasks preceding that, order is very important. My uglify task only works on the concatenated scripts.js file. If I were to run uglify before concat, it would minify the old scripts.js file before overwriting it with a new version concatentated from my other script files. Effectively, the minification would not occur. I avoid this by concatenating before minification.

Now, simply save and start running your new task! If you ever have need for more Grunt functionality, you should now be able to find a plugin, install it, configure it, and make it go using these techniques. As the proverb says, “If you give a man a Gruntfile, he’ll develop a web site. If you teach a man to write his own Gruntfile, that’s, like, way better.”

Superscript Your Ordinal Numbers (2nd, 3rd, Etc.) In WordPress Post Meta Data

Here we have an example of WordPress post meta data that uses an ordinal number for the date. In this case, November 2nd (that’s the ordinal part), 2012.

You may have noticed, though, that it’s really ugly. The “nd” is much taller than the number, and it’s not superscripted as we’d expect it to be. The whole thing just looks like a mess.

Typically, the suffix of the ordinal number is raised it above the baseline of the rest of the text. This is how we’re used to reading these numbers, but, if you want that effect in WordPress, you’ll have to add it yourself since the CMS doesn’t do it for you.

To do this, you need to wrap the suffix in <code class="language-none">&lt;sup&gt;</code> and style that accordingly in your stylesheets. Wrapping the suffix involves some escaping to prevent WP from interpreting the tag as part of the format string. Actually, it involves a great deal of escaping as shown in this example:
<div class="meta">
 <h6><strong>Posted on</strong> <?php the_time('F j\<\s\u\p\>S\<\/\s\u\p\>, Y') ?> <strong>by</strong> <?php the_author() ?> <strong><?php comments_popup_link( 'No Comments', '1 Comment', '% Comments', 'comments-link', '' ); ?></strong></h6>
</div>

Here, the capital ‘S’ is the ordinal part of the number. This gives you the ‘nd’ behind your 2 or the ‘rd’ behind your 3. To get this superscripted, you need to precede it with \<\s\u\p\> and follow it with \<\/\s\u\p\>. These are, respectively, the escaped opening and closing <sup> tags which will pass through the format string and make it into the final page output.

I also reduced the font size to 0.5em to make the ordinal text a bit smaller than the rest. The result is much nicer than the unstyled default version:

Start Your MAMP Dev Server With Grunt

I just started a new project that requires a PHP server, but the built-in PHP server used by grunt-php is not beefy enough. Instead, I need to run the MAMP server in order to test it.

To get around this, I installed the excellent grunt-exec plugin which allows Grunt to run arbitrary commands. Add these tasks to your Gruntfile to allow you to start and stop the MAMP server:

exec: {
      serverup: {
        command: '/Applications/MAMP/bin/start.sh'
      },
      serverdown: {
        command: '/Applications/MAMP/bin/stop.sh'
      }
}

Now, if you have a grunt task which runs watch, all you need to do is add serverup before watch and serverdown after it. The server will be started before Grunt begins the watch. It will be taken back down after you exit the watch task.

Git Deep Cuts

A friend and I have been working together to build a JavaScript game, and we’ve run into quite a few different roadblocks with Git version control. The software is incredibly flexible and powerful, but, with that flexibility, it brings a mind-boggling repertoire of commands that create a haystack of options around that needle that will have exactly your desired effect.

I’ve collected a few of the most common functions we find ourselves having to do on a regular basis and the somewhat unintuitive commands that will accomplish them.

Track a new remote branch

Frequently, one of your collaborators will start a new branch and push it to the remote repository. Now, you’d like to have a local branch tracking it.
git checkout -t <remote>/<whatever>

Undo a merge attempt with conflicts

If I try a merge that I thought would be simple, and find that it comes back with tons of conflicts, I may instead opt for a different merge strategy. Before I can try this, I’ll have to undo the merge in which I’m now entangled.
git merge --abort

Make a branch just like another

I feel there should be (and most likely is) a better way to do this. I want to be able to overwrite one branch with another. You could always delete the branch and then re-create it from your source branch, but that seems like a hassle. This is my current preferred method.

Switch to the branch you want to change (e.g. git checkout <destination_branch>)
git reset --hard <source_branch>

Delete a remote branch

Now, why didn’t I think to push to the remote and put a colon before the branch name in order to delete the remote branch? It’s all so clear now!

git push <remote> :<branch>
Note the colon before the branch name.

Stage a deleted file for commit

I wish this were as simple as adding the file as you would for a changed file. Instead, you need to remember a separate command to stage deleted files.
git rm <filename>

WordPress Image Resizing Without Php-gd

I ran into a problem recently on the very WordPress installation that runs this blog. After migration from my old hosting provider (Dreamhost) to my new VPS (DigitalOcean), WordPress was no longer resizing images.

I learned that this resizing is typically done by a PHP extension called php-gd. I tried to install the plugin using yum install php-gd, but the process ended complaining about a dependency which wasn’t being met. It appeared there was no way around this.

After posting the problem to StackExchange’s WordPress site, I was alerted to the fact that WordPress recently started using ImageMagick for image resizing.

Being a newcomer to Linux server administration, I still wasn’t sure what to do with this knowledge. I installed ImageMagick with yum install ImageMagick*.

Even with ImageMagic installed I still had no image resizing natively through WordPress (and I’m still not quite sure why this was the case). Luckily, I stumbled into a solution: the ImageMagick Engine plugin for WordPress. The plugin quickly found my ImageMagick install on the server and resizing was working once again.

A nice side-effect of this plugin was has an option to regenerate your thumbnails for existing uploads. This feature is provided because ImageMagick is apparently worlds better at scaling images than php-gd. It worked really nicely for me because I had no additional sizes for the images at all. I used this regenerate functionality to generate them for the first time.

As a bonus, check out the Simple Image Sizes plugin. It’s a great way to add custom sizes for your images that will be generated each time you upload.