11

My Problem

I'm writing a node module called a, which require()s a module b (written by a stranger). Unfortunately, a doesn't only need to access the public members - it also needs to access local variables declared in the scope of the module.

// a
var b = require('b');

console.log(b.public);
console.log(b.private); // undefined


// b
var c = require('c');
var stdin = process.stdin;

exports.public = true;
var private = true;

My Solution

// a
var b = require('b');
var srcPath = require.resolve('b');

console.log(b.public);
fs.readFile(srcPath, 'utf-8', function (err, src) {
    var box = {};
    var res = vm.runInNewContext(src, box, srcPath);
    console.log(box.private);
});

But vm doesn't run b as a module, so require() etc. aren't accessible from the context of the vm. So there are ReferenceErrors like:

    var res = vm.runInNewContext(src, box, scPath);
                 ^
ReferenceError: require is not defined
    at <module b>
    at <module a>
    at fs.readFile (fs.js:176:14)
    at Object.oncomplete (fs.js:297:15)

My Question

Which is the cleanest way to get the value of a local variable declared in another module? Ideas?

Thanks for your help.

fridojet
  • 1,276
  • 3
  • 15
  • 29

3 Answers3

5

you should probably mostly never have to do this, but there might be reasons.

you can hook the loader and inject javascript code to export what you want.

// let's say you have node_modules/foreignmodule/index.js
// and in that script there is a local (not-exported) function foreignfunction().

var path = require('path');
_oldLoader = require.extensions['.js'];
require.extensions['.js'] = function(mod, filename) {
    if (filename == path.resolve(path.dirname(module.filename), 'node_modules/foreignmodule/index.js')) {
        var content = require('fs').readFileSync(filename, 'utf8');
        content += "module.exports.foreignfunction=foreignfunction;\n";
        mod._compile(content, filename);
    } else {
        _oldLoader(mod, filename);
    }
};

require('foreignmodule').foreignfunction();
Moritz
  • 1,590
  • 13
  • 8
1

Check out my module import-locals

const patcher = new Patcher();
patcher.export("yourmodule", "Foo");
const { Foo } = require("yourmodule");
Zoe
  • 27,060
  • 21
  • 118
  • 148
AlexOwl
  • 869
  • 5
  • 11
-2

Just export the values properly

Module B

// b.js

// some local var
var foo = 'Bar';

exports.Foo = foo;
exports.Hello = 'World';

Module A

// a .js
b = require('./b');
console.log(b.Foo); //=> 'Bar'
console.log(b.Hello); // => 'World'

Read more about nodejs module.exports here

maček
  • 76,434
  • 37
  • 167
  • 198
  • 4
    **`I'm writing a node module called a, which require()s a module b (written by a stranger).`** - That means: `b` isn't written by me (and I don't want to get my hands dirty). – fridojet Dec 24 '12 at 10:55
  • 1
    It'd be nice if all strangers wrote their modules properly. But that isn't the case. Sometimes, you need to help them export the things they should've done. – Craig Brett Feb 22 '18 at 12:58