2013-07-10 44 views
31

如果我將文件的內容作爲內存中的字符串寫入磁盤,我會如何要求()一個文件?這裏有一個例子:從內存中的字符串加載node.js模塊

// Load the file as a string 
var strFileContents = fs.readFileSync("./myUnalteredModule.js", 'utf8'); 

// Do some stuff to the files contents 
strFileContents[532] = '6'; 

// Load it as a node module (how would I do this?) 
var loadedModule = require(doMagic(strFileContents)); 
+0

我沒有給你一個完整的答案,但你可以檢出的Node.js如何運行的模塊代碼。 https://github.com/joyent/node/blob/7373c4ddb7143fb7da75feda39c70788fb1bcfc7/src/node.js#L768也看看L813 – travis

回答

39
function requireFromString(src, filename) { 
    var Module = module.constructor; 
    var m = new Module(); 
    m._compile(src, filename); 
    return m.exports; 
} 

console.log(requireFromString('module.exports = { test: 1}')); 

看_compile,_extensions和_Load在module.js

+3

實際上你需要一件事情來讓'require'正常工作 - 在文件名上調用'Module._nodeModulePaths'(請參閱https://github.com/floatdrop/require-from-string)。 – floatdrop

-3

我認爲更好的方式來處理,這將是有,你可以設置事後參數...

比如裏面的文件:myUnalteredModule.js

exports.setChanges = function(args)... 

然後,你可以這樣做:

var loadedModule = require('myUnalteredModule'); 
loadedModule 
+0

我沒有這個選項。我必須能夠將模塊的內容修改爲一個字符串,並且我真的希望避免創建臨時文件。 – ZECTBynmo

33

的問題已經由安德烈回答,但我遇到了一個缺點,我不得不解決和這可能是爲他人的利益。

我希望記憶字符串中的模塊能夠通過require加載其他模塊,但模塊路徑被上述解決方案破壞(所以例如沒有發現針)。 我試圖找到一個很好的解決方案,以保持路徑,通過使用一些現有的功能,但我結束了硬連線的路徑:

function requireFromString(src, filename) { 
    var m = new module.constructor(); 
    m.paths = module.paths; 
    m._compile(src, filename); 
    return m.exports; 
} 

var codeString = 'var needle = require(\'needle\');\n' 
    + '[...]\n' 
    + 'exports.myFunc = myFunc;'; 

var virtMod = requireFromString(codeString); 
console.log('Available public functions: '+Object.keys(virtMod)); 

之後,我能夠從字符串化的模塊加載所有現有模塊。 任何意見或更好的解決方案高度讚賞!

+0

感謝分享,這節省了我大量的時間調試! – Deleteman

+3

它適用於單文件模塊!太糟糕了,它不適用於多文件模塊。我深入研究,結果發現每次調用'require'(例如,當用'requireFromString'編譯的「虛擬模塊」需要相對於自己的另一個文件時)總是最終[檢查真實文件](https://github.com/joyent/node/blob/master/lib/module .js#L134)在文件系統中。除非,我們可以通過'fs.statSync'和'fs.realpathSync'將文件路徑添加到虛擬文件路徑中,多文件模塊不可用。您可能會問爲什麼:我想通過網絡發送模塊... – Domi

+0

require.cache條目不存在 – xamiro

2

基於Andrey Sidorov &多米尼克解決方案,我不能要求字符串化模塊的事實令我感到難過,於是我建議這個版本*。

代碼:

void function() { 
    'use strict'; 

    const EXTENSIONS = ['.js', '.json', '.node']; 

    var Module, 
     path, 
     cache, 
     resolveFilename, 
     demethodize, 
     hasOwnProperty, 
     dirname, 
     parse, 
     resolve, 
     stringify, 
     virtual; 

    Module = require('module'); 
    path = require('path'); 

    cache = Module._cache; 
    resolveFilename = Module._resolveFilename; 

    dirname = path.dirname; 
    parse = path.parse; 
    resolve = path.resolve; 
    demethodize = Function.bind.bind(Function.call); 
    hasOwnProperty = demethodize(Object.prototype.hasOwnProperty); 

    Module._resolveFilename = function(request, parent) { 
     var filename; 

     // Pre-resolution 
     filename = resolve(parse(parent.filename).dir, request); 

     // Adding extension, if needed 
     if (EXTENSIONS.indexOf(parse(filename).ext) === -1) { 
      filename += '.js'; 
     } 

     // If the module exists or is virtual, return the filename 
     if (virtual || hasOwnProperty(cache, filename)) { 
      return filename; 
     } 

     // Preserving the native behavior 
     return resolveFilename.apply(Module, arguments); 
    }; 

    Module._register = function(request, parent, src) { 
     var filename, 
      module; 

     // Enabling virtual resolution 
     virtual = true; 

     filename = Module._resolveFilename(request, parent); 

     // Disabling virtual resolution 
     virtual = false; 

     // Conflicts management 
     if (hasOwnProperty(cache, filename)) { 
      error = new Error('Existing module "' + request + '"'); 
      error.code = 'MODULE_EXISTS'; 

      throw error; 
     } 

     // Module loading 
     cache[filename] = module = new Module(filename, parent); 
     module.filename = filename; 
     module.paths = Module._nodeModulePaths(dirname(filename)); 
     module._compile(stringify(src), filename); 
     module.loaded = true; 

     return module; 
    }; 

    stringify = function(src) { 
     // If src is a function, turning to IIFE src 
     return typeof src === 'function' 
      ? 'void ' + src.toString() + '();' 
      : src; 
    }; 
}(); 

void function() { 
    var Module, 
     parentModule, 
     child; 

    Module = require('module'); 

    // Creating a parent module from string 
    parentModule = Module._register('parent', process.mainModule, ` 
     module.exports = { 
      name: module.filename, 
      getChild: function() { 
       return require('child'); 
      } 
     }; 
    `); 

    // Creating a child module from function 
    Module._register('child', parentModule, function() { 
     module.exports = { 
      name: module.filename, 
      getParent: function() { 
       return module.parent.exports; 
      } 
     }; 
    }); 

    child = require('child'); 

    console.log(child === child.getParent().getChild()); 
}(); 

用法:

void function() { 
    var Module, 
     parentModule, 
     child; 

    Module = require('module'); 

    // Creating a parent module from string 
    parentModule = Module._register('parent', process.mainModule, ` 
     module.exports = { 
      name: module.filename, 
      getChild: function() { 
       return require('child'); 
      } 
     }; 
    `); 

    // Creating a child module from function 
    Module._register('child', parentModule, function() { 
     module.exports = { 
      name: module.filename, 
      getParent: function() { 
       return module.parent.exports; 
      } 
     }; 
    }); 

    child = require('child'); 

    console.log(child === child.getParent().getChild()); 
}(); 

*你可以看到,它包含一個函數格式化器提供一種方法來創建功能一些模塊。

+0

您可以添加一些註釋嗎? –

+1

剛剛完成...;) –

2

require-from-string package完成這項工作。

用法:

var requireFromString = require('require-from-string'); 

requireFromString('module.exports = 1'); 
//=> 1 
+1

我建議擴展您的答案,包括如何使用該模塊來解決OP的問題。 – brandonscript