Speeding Up My node.js Build

Saturday, May 2nd 2015

One day I say to you, “I have a large node.js project.”

“How large is it,” you ask with a slightly suggestive smirk on your face, with echoes of “That’s what she said” ringing quietly in the background.

I grimace because, quite frankly, I should have seen it coming. “My build time has exceeded 11 seconds, now.”

You gape at me increduously. “Node project? Are you sure you’re not programming C# in Visual Studio with build times like that?”

“Yeah. Node. Eleven seconds.”

“Dude,” you commisserate.

“I know.”

“What are you doing that takes that long?”

“I compile SASS, ES6 with babel, and minify some big client-side ECMAscript files. I do some other stuff, too, but that seems to take the most time.”

“And, that’s eleven seconds?”

“Yeah.”

You look at me. You just look at me. I hang my head in shame while we go off to the coffee shop.

Later that day, you send a text to me:

Have you thought about using gulp-newer?

https://github.com/tschaub/gulp-newer

I open Firefox Developer Edition and DuckDuckGo over to @tschaub’s GitHub page for gulp-newer. I read

A Gulp plugin for passing through only those source files that are newer than corresponding destination files.

I quikly reply to your text with a quick word of thanks and npm the package into my project. I find the gulp task that builds my ES6 server-side code and drop in the gulp-newer plugin.

1
2
3
4
5
6
7
8
9
10
11
12
gulp.task('build:es6-server', function () {
return gulp.src('./src/**/*.es6')
.pipe(newer({
dest: './build',
ext: '.js'
}))
.pipe(babel())
.pipe(rename(function (path) {
path.extname = '.js';
}))
.pipe(gulp.dest('./build'));
});

And, just like that, that task run by itself goes from three seconds to less than one second. I like where this is heading.

I head over to the SASS portion and hit a wall. That wall comes in the little streamed step that reads

1
.pipe(hash())

Darn it! I rename the file as a cache-busting measure for the static resources. I go back to the documentation and find that the gulp-newer plugin has a third option entitled map which allows me to translate the source relative paths to destination relative paths.

I can’t do it directly, I thought. I don’t know the value of the hash until after the transpiling, the step I want to avoid. Furthermore, the map option had to return synchronously, something that I find hard to do when programming, nowadays.

So, I went to the drawing board and listed out the steps I needed to do this.

  1. Figure out the destination directory.
  2. Create a glob to search for hash-suffixed files.
  3. If the glob has no results, then return nothing.
  4. If the glob has only one result, then return that one.
  5. If the glob has more than one result, use fs.statSync to find the one with the most recent modified time and return that one.

After stumbling a couple of times and checking the source code for gulp-newer, I completed the function. It took my 11-second build time down to 1.3 seconds after the initial build. Now, that’s a thing of beauty.

I send a couple of texts to you:

Thanks for that tip! It really helped my build time!

Check out the gist: https://gist.github.com/realistschuckle/0157389231c528015383