I enjoy experimenting with new tooling in my workflow.
Recently I wrote about Grunt and Takana, and I’ve been enjoying using both since then. Lately, however, I’ve been hearing a lot about Gulp. I can’t say I know much about how or why it’s different, but other folks seemed to be enamored with it, so I thought it was worth checking out.
Once I set everything up on a project I previously had configured with Grunt, I really liked how fast the new system was. I was seeing tasks that normally take two or more seconds being completed in milliseconds, sometimes even microseconds.
After my initial excitement, however, it became clear to me that the major pain of these tasks runners wasn’t the speed with which they complete their tasks, but the setup requirements.
As a freelancer, over the course of a few months, I may touch 10–15 projects. A typical web project of mine might have 100 or more files, depending on the complexity. Setting up Gulp or Grunt, even with the relatively small number of modules that I use, can instantly balloon that number to over 4000!
Even if I considered that acceptable for a project, spread that number across 10 different projects, and now we’re talking about over 30,000 files just to generate some CSS and uglify JavaScript. Files that, strictly speaking, aren’t even part of the project.
All those files can also add a performance penalty when searching across a project. Searching across 500 files is much faster than searching across 9,000. I know there are ways around this problem, like limiting the scope of a find or ignoring the “node_modules” folder, but this workflow still felt very wasteful to me.
I don’t collaborate with developers from all across the globe, and I also don’t work on a bunch of different projects with a huge variety of module and version requirements. I almost always want the most recent version of any given module and if I have to fix errors that come up during an upgrade, so be it. This process of maintaining a local install of every module feels akin to installing a new version of my text editor for every new project. Soon I would have 20 different versions of the same text editor sprinkled all over my hard drive, and while that may be ideal for some, it doesn’t work for me.
My goal was to try and figure out a way to run Gulp with a single “gulpfile.js” in the project folder. No “node_modules” directory, and no “package.json,” just one Gulp file per project. That way I can still customize the output and modules for different projects, but get to avoid having thousands of files and dependencies sitting in my project folder.
To accomplish this, I had to do a few things:
- Add the below to my profile. On a Mac this is the “.bash_profile” file in the Home directory, but both the location of the global Node modules and the profile file may vary between operating systems.
export NODE_PATH=/usr/lib/node_modules
- When installing modules via npm, always use the “-g” argument, this ensures that I can use the module in any project.
[sudo] npm install module -g
- The icky part, I had to modify Gulp a tiny bit to run the global version. I located “gulp.js” in “/usr/lib/node_modules/gulp/bin/” and, right after it defines the “localGulp” and “localPkg” variables, I added:
// use global gulp and modules if (argv.g) { localGulp = require('gulp'); localPkg = cliPkg; }
Update March 6, 2014: code as of 3.5.5
// use global gulp and modules if (argv.g) { env.modulePath = '/usr/lib/node_modules/gulp/'; env.modulePackage.version = cliPackage.version; }
Notice the “argv.g” conditional? I now run Gulp with a “-g” argument, just in case I need to do something locally later. The two lines inside basically say, use the global Gulp module you found in “NODE_PATH” and also, the local version and the global version are the same now.
Everything I’ve read says that this is not the preferred way of doing things, and I imagine more than one person may frown upon it, but for now this makes the most sense to me. Now I get to use Gulp and its modules as a system wide builder of files with every project, and all it takes is a single file.
Update August 20, 2014: The methods outlined in this article no longer work, and some readers have pointed out some better methods:
- Symlinking
This involves using the “ln -s” command to connect an external folder to the “node_modules” folder in your project. - NPM Link
This appears to be the official way to achieve almost exactly what I was initially aiming for, haven’t tried it myself yet.
Thanks to Kuba and Hunter for the help.