A month of gruntjs

I came across grunt a few months ago and was amazed at how little time I spent looking at my build process before it. JavaScript was already in control of my frontend, backend, mobile, system scripts, and now it’s the entire build process. It’s amazing.

I’ve got tasks set up that look as gorgeous as this

[cc lang=’js’]
registerTask(‘dev’, ‘lint server sass open:dev watch’);
registerTask(‘build’, ‘lint sass requirejs preprocess strip min’);
[/cc]

Here are 6 grunt tasks that I’ve published this month that, when combined with everything already out there, have accelerated my development a huge amount.


grunt-strip

grunt-strip allows you to strip out console.logs from your JavaScript source files. It also supports configuring other nodes you might want to strip out (like other debug libraries).

Example config

[cc lang=”js”]
grunt.initConfig({
strip : {
main : {
src : ‘htdocs/js/main.js’,
dest : ‘build/js/main.js’
nodes : [‘rcl’, ‘console’]
}
}
});
[/cc]


grunt-preprocess

grunt-preprocess allows you to exclude or include parts of JavaScript and HTML files via directives that optionally depend on environment configuration.

Example config

[cc lang=”js”]
grunt.initConfig({
preprocess : {
index : {
src : ‘htdocs/main.html’,
dest : ‘build/main.html’
}
}
});
[/cc]

Example Syntax

[cc lang=”html”]


I’m in production!


[/cc]

Example JavaScript Syntax

[cc lang=”js”]
// exclude
expensiveDebugCode();
// endexclude
[/cc]


grunt-open

grunt-open simply allows you to open urls or files via task configuration.

Example config

[cc lang=”js”]
grunt.initConfig({
open : {
dev : {
url : ‘http://127.0.0.1:8000/htdocs’
}
}
});
[/cc]

Allows for task chains like

[cc lang=”js”]
grunt.registerTask(‘dev’, ‘lint server open:dev watch’);
[/cc]


RCL

RCL (Remote Client Logging) is a tool written with grunt that allows you to log from your JavaScript application remotely to a terminal or web client. Visit rcljs.com for full documentation.


grunt-jasmine-runner

grunt-jasmine-runner is an tool to automate the generation and running of a jasmine-based specrunner through phantomjs.

Example config

[cc lang=”js”]
grunt.initConfig({
jasmine : {
src : ‘src/**/*.js’,
specs : ‘spec/**/*.js’
}
});
[/cc]


grunt-requiredir

grunt-require-dir allows you to automatically generate requirejs-compatible AMD modules out of a directory tree. This is useful for bucketing alike resources without resorting to an full precompilation step that might remove some of the benefit of AMD.

Example config

[cc lang=”js”]
grunt.initConfig({
‘require-dir’ : {
all : {
plugin : ‘tpl’,
src : ‘test/fixtures/texttree/**/*.tmpl’,
baseDir : ‘test/fixtures/texttree/’,
prefixDir : ‘customDir/’,
dest : ‘test/fixtures/texttree.js’
}
}
});
[/cc]

Generates output like

[cc lang=”js”]
define(function(require){
return {
‘A’ : {
‘one’ : require(“tpl!customDir/A/one.tmpl”),
‘two’ : require(“tpl!customDir/A/two.tmpl”)
},
‘bar’ : require(“tpl!customDir/bar.tmpl”),
‘foo’ : require(“tpl!customDir/foo.tmpl”)
};
});
[/cc]


All told, grunt has opened up massive possibilities for me with JavaScript development. There is nothing particularly revolutionary about it, it’s just a bunch of incredibly useful tools located in one glorious place. Having such an important step be written in JavaScript makes it trivial to recognize a need for a task, switch to writing and finishing that task, and get back to coding your app with no expensive context switch.

Why I use spaces over tabs

[UPDATE: I just got an email from someone saying they use tabs over spaces because visually aligning everything by repeatedly pressing the spacebar is too cumbersome. That is not what is meant by using spaces over tabs! Every IDE/editor supports replacing tab presses with a dynamic and variable number of spaces until you get to the appropriate indentation level. It would be insane if this misunderstanding turned out to be one of the cruxes of the issue.]


I never really understood the Tabs vs Spaces debate. When I first started programming I started using tabs but almost immediately realized they just weren’t suited for the job. They promise flexibility but, in practice, that flexibility is largely a lie and you tie other developers to your indentation style regardless. If you are tying developers in to a style, then why use tabs which can add unexpected confusion?

In the examples below, tab characters are colored a darker grey. Don’t get hung up on the coding style, the issues of alignment are what’s important and the code is terse for example’s sake.

Tabs with 4 char widths

This example shows an initial setup that uses a 4-width tab for nearly everything. It looks great and beautiful when you are set up for a 4-width tab, but try changing the tab width with the buttons below the example.


All the careful alignment goes to crap when you change the tab width. Yes, the fact that you can change the tab width is a great option to have, but if it requires you to reformat your code then it is not actually a real feature of using tabs, it’s the same situation in any scenario. Either manual or automatic reformatting all around.

Tabs with 2 char widths

Below is the same example as above, but optimized for a 2 character width tab. The exact same problem applies, but you can also see that it takes a different number of tabs to produce similar alignments.


Tabs for block indent only

The last entry on our tabstop tour is an example that only uses tabs for block level indentation, which some people use as a solution to the above problems. This still has its own issues when alignments occur across block level indentations (look at the last block) but also raises the simple question “why?” Block level indentation is the simplest thing for an IDE to take control over, and the actual act of block indentation is almost always hidden from the developer. It is also the easiest to reformat globally since the rules for that are relatively standard, configurable in most decent IDEs or, at the least, tolerable.

Even if this is the most tolerable solution, it introduces yet another wrench into enforcing style with other developers. Now you need to make sure a developer only uses tabs for block level indentation, and spaces for alignment purposes.


Spaces for tabs, two character indent

And here is the example that doesn’t include tabs at all, just spaces and a 2 tab indentation level. The benefit here is unmistakable intent.


There is no chance for confusion and what you see is what you get.

Contributors/teams do still need to set a common config as to the number of spaces for indentation, but that is better than assuming you don’t need to do that with tabs and getting conflicting code style regardless.

Personally, it really doesn’t matter to me as long as there is a standard. If you use tabs, then you still need to add the tab width you are coding with to coding guidelines. The reason I use spaces is because the environment is self-describing. If you see two spaces, you know the guideline is a two character indentation level. If you see a tab and effed up alignment, you need to experiment with a few configurations in order to find the style the original developers were coding towards.

(and yes, “flexible” or “smart” tabs sound awesome, but are impractical in mixed environments where IDE/editor support is so spotty)

if (someVar === otherVar) bar(); // If we're otherVar else if (isThing) otherFn(); // Do awesome stuff else quux(); // Do bad stuff!!

function bar() { if (anotherVariable === 42) { // If it's the answer anotherFunction(); } } }

if (someVar === otherVar) bar(); // If we're otherVar else if (isThing) otherFn(); // Do awesome stuff else quux(); // Do bad stuff!!

function bar() { if (anotherVariable === 42) { // If it's the answer anotherFunction(); } } }

if (someVar === otherVar) bar(); // If we're otherVar else if (isThing) otherFn(); // Do awesome stuff else quux(); // Do bad stuff!!

function bar() { if (anotherVariable === 42) { // Across block levels anotherFunction(); // it still breaks } } }

if (someVar === otherVar) bar(); // If we're otherVar else if (isThing) otherFn(); // Do awesome stuff else quux(); // Do bad stuff!!

function bar() { if (anotherVariable === 42) { // If it's the answer anotherFunction(); } } }

function updateExample(example,numTabs) { $('#'+example+' pre').html(TabFormatter.format($('#'+example+'Example').html(),numTabs,' ',1,'','')); }

(function(){ $('.tabExample button').click(function(evt){ var target = $(evt.target); var exampleId = target.parent().attr('id'); updateExample(exampleId,target.html()); }); updateExample('fourSpaceTab',4); updateExample('twoSpaceTab',2); updateExample('blockIndentOnly',2); $('#twoSpaces').html($('#twoSpaceExample').html()); })()

grunt-require-dir published to npm

I finally published the require-dir task to npm last night so you can now install it alongside your gruntfile with

npm install grunt-require-dir

This task automates the process of grouping files or modules into an AMD container compatible, at least, with requirejs. Essentially “require”-ing a whole directory. I find myself creating module namespaces to group like-content together and this automates that, previously manual, process.

It allows you to turn a directory tree like this
[cc]
|_ /fixtures
| |_ /texttree
| | |_ /A
| | | |_ one.tmpl
| | | |_ two.tmpl
| | |_ bar.tmpl
| | |_ foo.tmpl

[/cc]

into this

[cc lang=’javascript’]
define(function(require){
return {
‘A’ : {
‘one’ : require(“tpl!customDir/A/one.tmpl”),
‘two’ : require(“tpl!customDir/A/two.tmpl”)
},
‘bar’ : require(“tpl!customDir/bar.tmpl”),
‘foo’ : require(“tpl!customDir/foo.tmpl”)
};
});
[/cc]

Optical Illusions on Canvas

I’ve always loved optical illusions. Anything, really, that reminds me that I am not my brain.

I recently came across a old, great illusion that I have loved and have always wished that I could tweak to find out what point I start to lose grasp of the circles. I built a visualization in JavaScript (original static image) using canvas today that allows you to alter the properties of the circles, sizing, and rotation and it allows you to do just that.

The key to the illusion is the alternating rotation of the squares in each circle guiding your eyes in conflicting directions making you visualize separate spirals. If you uncheck ‘alternateRotation’ you get a more subtle illusion of one attached spiral, which is still cool.

Concentric Circle Illusion in JavaScript on Canvas

Running jasmine through phantomjs : grunt-jasmine-runner

I just pushed up a release of an internal runner I’ve been using for several weeks now. It started as a fork of @creynder’s grunt-jasmine-task but grew well beyond any appropriate scope of a pull request and figured I needed to take on the responsibility of maintaining it.

grunt-jasmine-runner [source]

There is base documentation at the source and the configuration is pretty straightforward. I put together an example application here : example grunt jasmine configuration

There is still a lot to come, but this was the best release point to prevent feature-paralysis.

Todomvc with Backbone.Marionette + Requirejs

I recently completed an app I’m planning on using for JavaScriptU in october and wrote it in the style of Addy Osmani’s TodoMVC repo so that it can be more easily compared to other frameworks.

Backbone.Marionette + RequireJS TodoMVC (source)

It differs a little bit in the style I would normally adhere to in order to make it as simple as possible for the sake of easy comparison. I tried to inject as little of my own bias in it as possible, except for very small file sizes and global jQuery and underscore.

Ergotron Workfit-S vs Workfit-A

Verdict : Workfit-S by a longshot (mostly).

Workfit-A

Workfit-A
Workfit-A

There is certainly nothing wrong with the Workfit-A, but it boils down to just being extra fickle for a level of motion and configuration that I don’t actually need. It wobbles a little and, while entirely manageable, it is not something I really wanted to consciously manage. The entire product is of phenomenal quality and it is excellent in its own regard, it’s just only extremely useful for people who really need the range of motion that the arm provides. If you are just looking for a convertible standing desk, then this is not it. If you are looking for a high-quality standing option with an extremely wide range of motion then this might be worthwhile. I could see this being useful in open-workplace environments where you might need to show a client or coworker your screen very easily.

Workfit-S

Workfit-s
Workfit-S

The Workfit-S, on the other hand, is exactly what I wanted in a standing desk. It is secure, sturdy, but still very portable so that you can feel comfortable moving the hardware around easily if you need to. The distance between the keyboard tray and the maximum monitor height also feels a bit greater, though I don’t have the actual distance. I ended up wedging the included T-shaped allen wrench underneath the keyboard tray so the keyboard is at a fairly extreme incline. This allows me to have an amazingly comfortable setup that actually eliminated my RSI pain within one week. The mouse ended up being used on the desk portion but, with the keyboard being lower with my alternate config, the height for everything still works very well.

Even without configuring the keyboard tray against instructions, it is still an excellent product. Unfortunately, for me, I committed to the Workfit-A at home and Workfit-S at work, so the one I prefer less actually came out of my own pocket.

The Workfit-A is still great and I am getting use out of it. It really needs a secure base so a cheap desk is only going to make the wobble worse. I ended up securing mine to the wall along with the desk and that did help a bit, but it’s also in the corner now so any benefit from the articulating arm is pretty much gone.

Overall, the experience with Ergotron products was incredible. I was happy with both purchases as soon as I opened the boxes. The build quality is really, truly excellent and everything goes together very smoothly. They both cost a lot ($499 each) but it is entirely worth it. You won’t feel the least bit ripped off.

Bringing back the food

The fifth day was enough for me to realize that my ability to lead a comfortable life in the routine I didn’t want to alter was being hampered. My motivation for work was drained, my speech was peculiarly off, and my fatigue levels were high.

The morning of the sixth day I weighed in at 169 pounds even, for an 11 pound loss. I’ll update some time later as to how much of that was put back on and how quickly.

I’m positive that there were numerous factors on top of eating that contributed to the poor feeling towards the end, but not eating affected my ability to regulate other stresses. My fatigue levels were higher than normal due to a hot and sweaty toddler who wasn’t sleeping well combined with a new standing desk at work. One change that didn’t occur to me until much later than it should have was that I almost never took breaks at work when food was cut out. I didn’t take a lunch break, I didn’t take coffee breaks, drink breaks, random breaks, I just stood and worked nearly the entire day. That alone, even while properly nourished, is going to lead to fatigue and decreased motivation.

My diet will likely be permanently affected. I liked the feeling I had earlier in the week, it was almost like freedom. Freedom from food. Since I no longer intend to eat as little as I can stomach (literally), the experiment is over at about 133 hours in (five and a half days).

Day 5 and first doubts

I woke up feeling like crap today and mostly attribute that to my son kicking me in the face all night, but it is definitely compounded by not eating and probably the fact that my wife was cooking bacon this morning, a smell that is still intoxicating. I took a bite, I’m only human.

I weighed in at 170.8 for a 1.2 pound loss.

I ate a handful of raw baby spinach (20 cal)  and had one small bite of bacon (approximating 1/5th a slice, 9 cal)  to see how that would kickstart the day. It did reasonably well but at about 2:00 I started to lose focus and feel drained again.

My speech is something that is deteriorating as well. My ability to get words out and to recall words quickly enough to speak is noticeably lessened. I’m not sure if it’s yet noticeable to other people, but I definitely feel it. I’ll see how I feel tomorrow but if better sleep doesn’t remedy this then tomorrow may be my last day.

Some people have likened this experiment to the the master cleanse but the significant difference is the maple syrup in each glass of the drink accounts for a little over 100 calories. When 6-12 glasses are recommended a day, you are consuming 600-1200 calories to provide energy to your body, which is a lot!

For comparison, our current calorie tally:

  • ~63 calories for the two Buitoni ravioli (approximating a quarter cup)
  • 11 calories for the raw parsley (about half a cup)
  • 20 calories for 6 asparagus spears
  • 68 calories for two cans of V8
  • 350 calories for a little over 2 bottles of shock top (!!!)
  • 4 calories for a pistachio
  • 20 calories for 1.5 cups spinach (above)
  • 9 calories for a bite of bacon (above)
  • 40 calories of half and half (approximated) for small coffees
  • 4 calories coffee (2 8oz cups)
  • 2 packets sugar

That comes out to 591 calories over the past 5 days. Given 2600 calories being my recommended daily amount (choosemyplate.org), I’m averaging about 4% of my recommended intake and about 118 calories a day. Half of that consumption was centered around a 2 hour period, too. The last 2 days have seen around 50 calories total.

One thing I didn’t account for was how the sleep rhythm we have adopted in modern society is probably very counterproductive to hibernation mode and conserving limited energy. I can’t nap when I want and I need to force myself to stay awake for a significant portion of the day. Oh how I would love a nap.

Fooling around on app.net

I’ve flopped back and forth on whether or not App.net is a good idea and I think I’m solidly landing on the belief that it is great. Or at least not bad. I don’t know. Maybe.

Initially the thought of a pay-for social network sounded ridiculous but as I reevaluate the importance of social networks to me and the value I get out of them, it seems silly to let them be in the control of companies looking to sell your data and put ads in your face.

The part that concerns me is if app.net requires more money to run than they are pulling in. Are they going to charge more? Are ads inevitable? What if I can’t pay? Do I disappear?