Load "Vanilla" Javascript Libraries into Node.js
Here's what I think is the 'rightest' answer for this situation.
Say you have a script file called quadtree.js
.
You should build a custom node_module
that has this sort of directory structure...
./node_modules/quadtree/quadtree-lib/./node_modules/quadtree/quadtree-lib/quadtree.js./node_modules/quadtree/quadtree-lib/README./node_modules/quadtree/quadtree-lib/some-other-crap.js./node_modules/quadtree/index.js
Everything in your ./node_modules/quadtree/quadtree-lib/
directory are files from your 3rd party library.
Then your ./node_modules/quadtree/index.js
file will just load that library from the filesystem and do the work of exporting things properly.
var fs = require('fs');// Read and eval libraryfiledata = fs.readFileSync('./node_modules/quadtree/quadtree-lib/quadtree.js','utf8');eval(filedata);/* The quadtree.js file defines a class 'QuadTree' which is all we want to export */exports.QuadTree = QuadTree
Now you can use your quadtree
module like any other node module...
var qt = require('quadtree');qt.QuadTree();
I like this method because there's no need to go changing any of the source code of your 3rd party library--so it's easier to maintain. All you need to do on upgrade is look at their source code and ensure that you are still exporting the proper objects.
There is a much better method than using eval
: the vm
module.
For example, here is my execfile
module, which evaluates the script at path
in either context
or the global context:
var vm = require("vm");var fs = require("fs");module.exports = function(path, context) { context = context || {}; var data = fs.readFileSync(path); vm.runInNewContext(data, context, path); return context;}
And it can be used like this:
> var execfile = require("execfile");> // `someGlobal` will be a global variable while the script runs> var context = execfile("example.js", { someGlobal: 42 });> // And `getSomeGlobal` defined in the script is available on `context`:> context.getSomeGlobal()42> context.someGlobal = 16> context.getSomeGlobal()16
Where example.js
contains:
function getSomeGlobal() { return someGlobal;}
The big advantage of this method is that you've got complete control over the global variables in the executed script: you can pass in custom globals (via context
), and all the globals created by the script will be added to context
. Debugging is also easier because syntax errors and the like will be reported with the correct file name.
The simplest way is: eval(require('fs').readFileSync('./path/to/file.js', 'utf8'));
This works great for testing in the interactive shell.