2013-05-31 73 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

相關問題