Created
January 3, 2015 01:19
-
-
Save Xananax/d076806b6fe75a778ce0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/********************************************************** | |
Utility to load modules while passing context. | |
Equivalent to using 'require()', but modules | |
aren't cached, so it can be used to load files that | |
change. | |
The second benefit is passing a context object, which | |
allows to have globals without polluting node.js | |
global space. | |
The default context object passes require & console. | |
You can pass your own with your own functions, or | |
pass your custom require(module) to swap modules | |
on the fly (say, replace fs by a virtual fs). | |
Works synchronously and asynchronously. | |
usage: | |
load(filePath) | |
// equivalent to require(filePath) | |
load(filePath,callback) | |
// Async require | |
load(filePath,context) | |
// equivalent to require, but with a custom context | |
// context is a hash that is used as globals | |
load(filePath,context,callback) | |
// Async require + custom context | |
if you've already read the file contents, you | |
can use the alternative load.run function | |
load.run(filePath,contents) | |
// equivalent to require(filePath) | |
load.run(filePath,contents,context) | |
// custom context | |
load.run(filePath,contents,callback) | |
// async require | |
load.run(filePath,contents,context,callback) | |
// async require + custom context | |
**********************************************************/ | |
var vm = require('vm') | |
, fs = require('fs') | |
, path = require('path') | |
; | |
function resolveModule(filePath,name){ | |
if (name.charAt(0) !== '.') return name; | |
return path.resolve(path.dirname(filePath), name); | |
} | |
function extend(context,defaultContext){ | |
if(!context.hasOwnProperty('module')){context.module = defaultContext.module;} | |
if(!context.hasOwnProperty('exports')){context.exports = defaultContext.exports;} | |
if(!context.module.hasOwnProperty('exports')){context.module.exports = defaultContext.exports;} | |
for(var n in defaultContext){ | |
if(n == 'module' || n=== 'exports'){continue;} | |
if(!context.hasOwnProperty(n)){ | |
context[n] = defaultContext[n]; | |
} | |
} | |
return context; | |
} | |
function isEmpty(obj){ | |
if((typeof obj == 'undefined') || obj == ''){return false;} | |
if(typeof obj == 'function'){return obj;} | |
for (var key in obj) { | |
if (obj.hasOwnProperty(key)){return obj;} | |
} | |
return false; | |
} | |
function virtualModule(filePath,contents,context,callback){ | |
var exports = {} | |
, defaultContext = { | |
require: function fakeRequire(name) { | |
return require(resolveModule(filePath,name)); | |
} | |
, console:console | |
, exports:exports | |
, module:{ | |
exports:exports | |
} | |
} | |
; | |
context = (context && extend(context,defaultContext)) || defaultContext; | |
var script = vm.createScript(contents,filePath); | |
try{ | |
script.runInNewContext(context); | |
var returned = isEmpty(context.exports) || context.module.exports; | |
if(callback){callback(null,returned);} | |
return returned; | |
}catch(e){ | |
e.message+=' in `'+filePath+'`'; | |
if(callback){return callback(err);} | |
throw err; | |
} | |
} | |
function LoadModule(filePath,context,callback){ | |
if(typeof context == 'function'){ | |
callback = context; | |
context = null; | |
} | |
if(!callback){ | |
var contents = fs.readFileSync(filePath,{encoding:'utf8'}); | |
return virtualModule(filePath,contents,context); | |
} | |
fs.readFile(filePath,{encoding:'utf8'},function(err,contents){ | |
if(err){return callback(err);} | |
virtualModule(filePath,contents,context,callback); | |
}); | |
}; | |
LoadModule.run = virtualModule; | |
module.exports = LoadModule; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment