Search code examples
javascriptnode.jscommonjs

Load "Vanilla" Javascript Libraries into Node.js


There are some third party Javascript libraries that have some functionality I would like to use in a Node.js server. (Specifically I want to use a QuadTree javascript library that I found.) But these libraries are just straightforward .js files and not "Node.js libraries".

As such, these libraries don't follow the exports.var_name syntax that Node.js expects for its modules. As far as I understand that means when you do module = require('module_name'); or module = require('./path/to/file.js'); you'll end up with a module with no publicly accessible functions, etc.

My question then is "How do I load an arbitrary javascript file into Node.js such that I can utilize its functionality without having to rewrite it so that it does do exports?"

I'm very new to Node.js so please let me know if there is some glaring hole in my understanding of how it works.


EDIT: Researching into things more and I now see that the module loading pattern that Node.js uses is actually part of a recently developed standard for loading Javascript libraries called CommonJS. It says this right on the module doc page for Node.js, but I missed that until now.

It may end up being that the answer to my question is "wait until your library's authors get around to writing a CommonJS interface or do it your damn self."


Solution

  • 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.