Skip to content

Instantly share code, notes, and snippets.

@leizongmin
Created August 1, 2012 05:28
Show Gist options
  • Save leizongmin/3223978 to your computer and use it in GitHub Desktop.
Save leizongmin/3223978 to your computer and use it in GitHub Desktop.
使用指定上下文来加载文件
/**
* 被加载的模块
*/
console.log('require file: random=' + random);
/**
* 主模块
*/
var requireWithContext = require('./require_with_context');
var random = Math.random();
console.log('main: random=' + random);
var file = requireWithContext('./file.js', {
random: random // 此为要传给该文件的变量,在该文件内可以直接使用
});
'use strict';
/**
* 使用指定的环境变量来加载文件
*
* @author 老雷<[email protected]>
*/
var fs = require('fs');
var path = require('path');
var vm = require('vm');
var Module = require('module');
/**
* 载入程序文件,并删除其缓存
*
* @param {string} filename 文件名
* @param {object} context 环境变量
* @param {object} parent 父模块
* @return {object}
*/
module.exports = function (filename, context, parent) {
var self = this;
filename = path.resolve(filename);
// 如果没有指定环境变量和父模块,则清除缓存模块并加载
if (!context && !parent) {
/*debug debug('require no cache file: ' + filename); */
delete require.cache[filename];
var m = require(filename);
delete require.cache[filename];
return m;
}
// 否则,使用指定的环境变量和父模块来载入文件
else {
/*debug debug('require specified context file: ' + filename); */
if (typeof context !== 'object')
context = {}
// 复制全局变量
var sandbox = merge(global, context);
return requireWithContext(filename, sandbox, parent);
}
}
/**
* 使用指定的沙箱环境来载入模块文件
*
* @param {string} filename 文件名
* @param {object} sandbox 沙箱
* @param {object} parent 父对象
* @return {object}
*/
var requireWithContext = function (filename, sandbox, parent) {
try {
if (!parent)
parent = {require: require}
if (!sandbox)
sandbox = {}
// 读取代码
var code = fs.readFileSync(filename, 'utf8');
// 模拟require()环境
sandbox.module = new Module(filename, parent);
sandbox.exports = sandbox.module.exports;
sandbox.__dirname = path.dirname(filename);
sandbox.__filename = filename;
sandbox.module.filename = filename;
sandbox.module.paths = Module._nodeModulePaths(sandbox.__dirname);
sandbox.global = sandbox;
sandbox.root = root;
sandbox.require = function (path) {
var f = sandbox.require.resolve(path);
return parent.require(f);
}
sandbox.require.resolve = function(request) {
return Module._resolveFilename(request, sandbox.module);
}
sandbox.require.main = process.mainModule;
sandbox.require.extensions = Module._extensions;
sandbox.require.cache = Module._cache;
// 运行代码
vm.runInNewContext(code, sandbox, filename);
// 返回模块输出
return sandbox.module.exports;
}
catch (err) {
// 如果是语法错误,则尝试输出更详细的信息,比如出错的位置
if (isSyntaxError(err)) {
process.stdout.write('--------------------------------------------------------------------------------\n');
process.stdout.write(err.toString() + '\n');
try {
require(filename);
}
catch (e) { }
process.stdout.write('--------------------------------------------------------------------------------\n');
}
throw new Error(err.toString() + '\n at ' + filename);
}
}
/**
* 判断异常是否为语法错误
*
* @param {Error} e
* @return {bool}
*/
var isSyntaxError = function (e) {
// Convert error to string
e = e && (e.stack || e.toString());
return e && e.match(/^SyntaxError/) &&
!(e.match(/^SyntaxError: Unexpected token .*\n/) &&
e.match(/\n at Object.parse \(native\)\n/));
};
/**
* 合并多个对象
*
* @param {object} obja
* @param {object} objb
* @return {object}
*/
var merge = function () {
var ret = {};
for (var i in arguments) {
var obj = arguments[i];
for (var j in obj) {
ret[j] = obj[j];
}
}
return ret;
};
@leizongmin
Copy link
Author

运行: node main.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment