Using Browserify without a node_modules directory
Posted on Sat 19 July 2014 in JavaScript
NPM and Bower are pretty awesome; they provides both NodeJS and web developers a way to share CommonJS modules (aka packages) amongst code-bases without relying on copy/pasting concatenated .js files. Browserify fills in the missing link for deploying an application to the web; it gathers up disparate CommonJS modules which NPM/Bower resolved and bundles them up into a single .js file ready to be dropped into a <script> tag.
When writing CommonJS code, you can import files by two methods, either relativley, (typically used internally inside your app / module), ie:
var MakePizzaCommand = require("./commands/MakePizzaCommand");
Or you can import entire libraries, eg: those which were resolved by Bower / NPM
var reqwest = require("reqwest");
In the first example, Browserify will locate the MakePizzaCommand object by reading the file relative from the host file making the require call; ie:
├── app.js <-- makes the require call
└── commands
└── MakePizzaCommand.js <-- gets included
In the second example, Browserify identifies that you are not referencing a local file (as the require argument does not look like a path), so instead it starts looking up the directory tree for a node_modules folder which contains a subfolder for the module the host file making the require call is trying to import.
pizzajs
├── node_modules <-- 3. found it! now look in each subfolder
│ │ for a package.json file with the name of
│ │ the module we are trying to import.
│ └── reqwest
│ └── package.json
│
├── src <-- 2. no `node_modules` dir here either, so look in the
│ │ parent dir (pizzajs)
│ │
│ ├── app.js <-- 1. makes the require call, no `node_modules` dir
│ │ here so look in parent dir (src)
│ └── commands
│ └── MakePizzaCommand.js
└── test
But what if you don't want to use NPM / Bower to resolve your dependencies? AFAIK you have two options avaiable to you:
-
Create a
node_modulesfolder in your project and copy all your CommonJS libraries into it during the build process; note that thenode_modulesfolder must sit either adjacent to your project's sources (src) or in a ancestor folder. -
Make use of the
NODE_PATHenvironment variable, this provides another absolute URL for browserify to use when looking for CommonJS modules. This allows you to pull off the following folder structure (which may suit none-javascript-based build systems better):
pizzajs
├── lib
│ └── reqwest
│ └── package.json
└── src
└── app.js
If you're using Grunt, you can easily set the NODE_PATH environment variable with each build by adding the following to the top of your Gruntfile.js:
// Set NODE_PATH env-var to the cwd.
process.env["NODE_PATH"] = __dirname;
module.exports = function(grunt) {
grunt.initConfig({ .. });
});