2013-07-10 25 views
31

Làm cách nào để yêu cầu() một tệp nếu tôi có nội dung của tệp dưới dạng chuỗi trong bộ nhớ, mà không ghi nó ra đĩa? Dưới đây là một ví dụ:Tải mô-đun node.js từ chuỗi trong bộ nhớ

// 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

Tôi không có một câu trả lời đầy đủ cho bạn, nhưng bạn có thể kiểm cách Node.js chạy mã module. https://github.com/joyent/node/blob/7373c4ddb7143fb7da75feda39c70788fb1bcfc7/src/node.js#L768 cũng xem tại L813 – travis

Trả lời

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}')); 

xem _compile, _extensions và _load trong module.js

+3

Thực ra bạn cần thêm một thứ nữa để làm cho 'require' hoạt động đúng - gọi' Module._nodeModulePaths' trên tên tập tin (xem https://github.com/floatdrop/require-from-string). – floatdrop

-3

Tôi nghĩ rằng cách tốt hơn để tiếp cận này sẽ có một tham số mà bạn có thể thiết lập sau đó ...

như bên trong file: myUnalteredModule.js

exports.setChanges = function(args)... 

Sau đó, bạn có thể làm:

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

Tôi không có tùy chọn đó. Tôi có thể sửa đổi nội dung của mô-đun dưới dạng chuỗi và tôi thực sự muốn tránh tạo các tệp tạm thời. – ZECTBynmo

33

Câu hỏi đã được trả lời bởi Andrey, nhưng tôi gặp phải một thiếu sót mà tôi phải giải quyết và điều này có thể khiến người khác quan tâm.

Tôi muốn mô-đun trong chuỗi ghi nhớ có thể tải các mô-đun khác qua require, nhưng đường dẫn mô-đun đã bị hỏng với giải pháp trên (ví dụ: kim không được tìm thấy). tôi đã cố gắng để tìm một giải pháp tinh tế để duy trì các đường dẫn, bằng cách sử dụng một số chức năng hiện có nhưng tôi đã kết thúc với dây cứng đường dẫn:

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)); 

Sau đó tôi đã có thể tải tất cả các module hiện có từ các mô-đun chuyển đổi thành chuỗi. Mọi nhận xét hoặc giải pháp tốt hơn đều được đánh giá cao!

+0

Cảm ơn bạn đã chia sẻ, điều này đã tiết kiệm rất nhiều thời gian cho tôi! – Deleteman

+3

Nó hoạt động tốt cho các mô-đun tập tin đơn! Quá tệ, nó sẽ không hoạt động đối với các mô-đun đa tệp. Tôi đào sâu vào nó, và chỉ ra rằng mọi cuộc gọi đến 'yêu cầu' (ví dụ:khi một "mô-đun ảo" được biên dịch với 'requireFromString' yêu cầu một tệp khác liên quan đến chính nó) sẽ luôn luôn kết thúc [kiểm tra một tệp thực] (https://github.com/joyent/node/blob/master/lib/module .js # L134) trong hệ thống tệp. Trừ khi, chúng ta có thể thêm đường dẫn tệp ảo theo cách 'fs.statSync' và' fs.realpathSync' sẽ chọn chúng, các mô-đun nhiều tệp nằm ngoài tầm với. Bạn có thể hỏi tại sao: Tôi muốn gửi các mô-đun qua mạng ... – Domi

+0

mục nhập require.cache bị thiếu – xamiro

2

Dựa trên Andrey Sidorov & Giải pháp thống trị, tôi rất buồn vì không thể yêu cầu mô-đun được xâu chuỗi, sau đó tôi đề xuất phiên bản này *.

Code:

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()); 
}(); 

Cách sử dụng:

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()); 
}(); 

* như bạn có thể thấy, nó chứa một formater chức năng cung cấp một cách để tạo ra một số module từ chức năng.

+0

bạn có thể thêm một số nhận xét cho điều này không? –

+1

Chỉ cần thực hiện ...;) –

2

require-from-string package thực hiện công việc.

Cách sử dụng:

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

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

Tôi khuyên bạn nên mở rộng câu trả lời của mình để bao gồm ví dụ về cách bạn sử dụng mô-đun đó để giải quyết vấn đề của OP. – brandonscript

Các vấn đề liên quan