While developing my side project in AngularJS, I ran into a problem with building distribution of the app. Everything seemed to work just fine: the unit and integration tests on my machine, the build process on Travis CI, the deployment to S3 (I’ll be switching to CloudFront soon, though). I sent a message to my tester/wife, asking for a quick review. I received a single complaint: why does it load so slow?
I ran the developer plugin in Chrome, and found the reason: the AngularJS minified script took nearly 1MB with no compression (thank you, S3!). It turned out that grunt-google-cdn plugin, wrapping google-cdn util, had not been updated for quite a long time, resulting in downloading the AngularJS library from bower, instead of a CDN. In fact, it was too late to just dump the version in the dependencies - the API had changed, and it was already easier just to write own plugin from scratch.
When you are to write your own Grunt plugin, you are probably aware of the JS ecosystem. I am refering here to NPM (Node.js Package Manager), which is a package manager for node.js. If you want your plugin (or in fact any node.js module) to be available for other developers, you have to publish it there. You can easily google for advice how you should do that, but I decided to go with Travis CI, which can automatically publish your code to NPM. So, I initialized a repository grunt-google-cdnify and configured Travis CI for auto-deployment to NPM from git branch master (in opposite for develop branch for development).
Having the deployment configured, the plugin initialization is really easy. All you have to do is:
The first command install grunt-init
package, the second one installs the template for a Grunt plugin, and the last one initializes that. During initialization you will be asked couple of questions, regardings names, license, your email etc. All of the steps can be found on Grunt website, which you should defintitely visit before starting development of your own plugin. It also contains info on naming your plugin with one important note: do not prefix your plugin with grunt-contrib. It is reserved for Grunt development team.
The template comes with sample test written in nodeunit. You can probably call that an integration test, as the idea is to run your plugin against a set of arguments, just like in a real Grunt task, and then compare the results. In my Gruntfile.js
it looked like this:
As you can see, my cdnify
task is run against two sets of arguments (yes, I have two test cases). First, the plugin is run, then the nodeunit
task compares the results with expected values.
My plugin was rather straightforward, but obviously not all plugins are like that. In such case, you will probably need to write some unit tests.
To be honest, that was the easy part, at least for my plugin. What I did was basically registering a multitask, that run the google-cdn
for replacing the JS libraries from bower with CDN versions. Easy as that, I fell into a trap of asynchronicity.
It turns out that Grunt runs its tasks asynchronously, which can lead to problems with bower cache access. In order to do that, Grunt provides a way to tell that the task is asynchronous:
It works fine, but for working on multiple files in my case I had to use additional node.js module async
. It helps when working with asynchronous code, and is definitely worth checking out. It contains each
method, which allows you to run asynchonous code on collection of objects, and do additional execution upon all the previous job were finished.
Writing Grunt plugins isn’t really very hard. Hope I cleared out a little how one does that. Have fun writing ours!
Grunt-google-cdnify is available here.
comments powered by Disqus