2013-05-31 47 views
0

我期待monkey-patch require()用我自己的函数替换它的文件加载。我想,在内部需要(是模块)确实是这样的:更改nodejs如何require()获取文件

  1. 转换是模块到一个文件路径
  2. 负载为一个字符串
  3. 编译字符串转换成一个模块对象的文件路径,并设置各种全局正确

我正在寻找替换步骤2而不重新执行步骤1 + 3.看看公共API,需要()哪些做1-3,和require.resolve()哪个做1。一种将步骤2与步骤3分离的方法?

我已经看过require嘲弄工具的来源,例如mockery - 他们似乎正在做的是用一个函数替换require(),该函数拦截某些调用并返回用户提供的对象,并传递其他调用本地require()函数。

对于上下文,我试图编写一个函数require_at_commit(module_id,git_commit_id),它加载了一个模块和任何该模块的要求,因为它们是在给定的提交。

我想要这个函数,因为我希望能够编写某些函数,这些函数a)依赖于我的代码库的各个部分,并且b)保证当我演变我的代码库时不会改变。我想在各个时间点“冻结”我的代码,所以认为这可能是一种避免打包20个代码库副本的简单方法(另一种方法是使用“my_code_v1”:“git:// .. 。“在我的package.json中,但我觉得这将是臃肿和缓慢的20个版本)。

更新:

所以对于加载模块的源代码是在这里:https://github.com/joyent/node/blob/master/lib/module.js。具体来说,要做这样的事情,你需要重新实现Module._load,这非常简单。然而,还有一个更大的障碍,那就是第1步,将module_id转换为文件路径,实际上比我想象的更难,因为resolveFilename需要能够调用fs.exists()来知道在哪里终止搜索...所以我不能只替换单个文件,我必须替换整个目录,这意味着只需将整个git修订版导出到目录并在该目录下指向require(),而不是重写require() 。

更新2:

端了完全采用了不同的方法...看到我的回答下面添加

+0

你可以改为在你的git提交中包含'node_modules'文件夹吗?这样,当你签出一个提交时,你可以获得整个项目的完整快照,包括特定的模块版本。在这里看到更多的信息http://www.futurealoof.com/posts/nodemodules-in-git.html – Noah

+0

谢谢...我试图从我的代码的更高版本访问我的代码的早期版本,虽然,所以我认为这不会起作用。另外,当我开始使用nodejs时,我沿着检查node_modules进入git的路径,这似乎以非常糟糕的方式对二进制编译模块造成严重破坏...... – josh

回答

0

因此,不是好惹的节点需要()模块,我最后做的是归档给出承诺,我需要到一个文件夹。我的代码看起来像这样:

# commit_id is the commit we want 
# (note that if we don't need the whole repository, 
# we can pass "commit_id path_to_folder_we_need") 
# 
# path is the path to the file you want to require starting from the repository root 
# (ie 'lib/module.coffee') 
# 
# cb is called with (err, loaded_module) 
# 
require_at_commit = (commit_id, path, cb) -> 
    dir = 'old_versions' #make sure this is in .gitignore! 
    dir += '/' + commit_id 

    do_require = -> cb null, require dir + '/' + path 

    if not fs.existsSync(dir) 
     fs.mkdirSync(dir)    
     cmd = 'git archive ' + commit_id + ' | tar -x -C ' + dir 
     child_process.exec cmd, (error) -> 
      if error 
       cb error 
      else 
       do_require() 
    else 
     do_require() 
1

可以使用require.extensions机制。这就是咖啡脚本coffee命令可以如何加载.coffee文件,而不会将.js文件写入磁盘。

下面是它如何工作的:

https://github.com/jashkenas/coffee-script/blob/1.6.2/lib/coffee-script/coffee-script.js#L20

loadFile = function(module, filename) { 
    var raw, stripped; 
    raw = fs.readFileSync(filename, 'utf8'); 
    stripped = raw.charCodeAt(0) === 0xFEFF ? raw.substring(1) : raw; 
    return module._compile(compile(stripped, { 
     filename: filename, 
     literate: helpers.isLiterate(filename) 
    }), filename); 
    }; 

    if (require.extensions) { 
    _ref = ['.coffee', '.litcoffee', '.md', '.coffee.md']; 
    for (_i = 0, _len = _ref.length; _i < _len; _i++) { 
     ext = _ref[_i]; 
     require.extensions[ext] = loadFile; 
    } 
    } 

基本上,假设你的模块有一组著名的扩展,你应该能够使用接受该模块的功能的这种模式和文件名,做任何你需要的加载/转换,然后返回一个模块对象。

这可能会或可能不足以满足您的要求,但从您的问题中诚实地说,您听起来像是在杂草丛生的地方远离编程世界的其他地方(不要那么苛刻,它是只是我最初的反应)。

+0

谢谢,我认为module._compile可能是我正在寻找。我会更新问题,如果我得到它的工作。另外,对于我处于一个奇怪的角落,你可能完全正确 - 做任何我想做的事情的简单方法(冻结我的代码库的连续旧版本并从最新版本引用它们)会很有帮助。 – josh

相关问题