Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

createScript, __filename and require with relative paths #2525

Closed
WolfgangKluge opened this issue Jan 12, 2012 · 7 comments
Closed

createScript, __filename and require with relative paths #2525

WolfgangKluge opened this issue Jan 12, 2012 · 7 comments
Labels

Comments

@WolfgangKluge
Copy link

As mentioned in #439, the filename parameter of createScript, runInNewContext (and all the vm.* - members) is informational only (not as stated in the docs "as if it were loaded from filename"). So the question is, how to solve something like

var vm = require("vm"),
    path = require("path"),
    code = "var test = require('./subtest.js')",
    context = { require: require };

var script = vm.createScript(code, path.resolve("subfolder/fileInSubfolder.js"));
script.runInNewContext(context);

where subtest.js is a file in subfolder.
The relative path to ./subtest.js cannot be resolved, because current module filename still points to the current test file (and not to fileInSubfolder.js).

I also tried it with Module.wrap, but I don't know, what I should provide as module-parameter. Is there a documentation for wrap (or examples)?

@1602
Copy link

1602 commented Jan 12, 2012

This is my unlucky way to figure out require behavior with relative paths: https://gist.github.com/1599423 am I missing something?

@bnoordhuis
Copy link
Member

I've updated the vm documentation in 465e22e.

Re: running node.js code in a sandbox, why don't you use child processes?

@1602
Copy link

1602 commented Jan 12, 2012

I don't need separate processes, just more control on script execution context. This is for RailwayJS framework.

@1602
Copy link

1602 commented Jan 12, 2012

Maybe you can suggest some solution for my use case? I need to run some code in sandbox with ability to require some other paths relatively, as demonstrated in my gist (https://gist.github.com/1599423). The only way to do it is ugly hack: pass customized require to context of executable script, like that:

var dirname = path.dirname(filename);
context.require = function (apath) {
    // convert relative paths to absolute
    if (apath.match(/^\.\.?\//)) {
        return require(dirname + '/' + apath);
    } else {
        return require(apath);
    }
};

@isaacs
Copy link

isaacs commented Jan 12, 2012

The vm functions do not use the module system. If I were you, I'd try to do this by hijacking the module loader stuff from require("module") directly.

It's internal, and mostly undocumented, so you'll just have to RTFS in node's lib/module.js, I'm afraid. But it's also extremely stable, and very unlikely to ever change again. An approach like this might be a start (untested, most likely has bugs)

// railway.js
var Module = require("module").Module
var path = require("path")
var target = path.resolve(__dirname, "target.js")
var vm = require("vm")
var ctx = { railway: "stuff" }
var mod = new Module(target, module) // I forget if the parent ref is a module or a path string...
ctx.module = mod
ctx.__filename = target
ctx.__dirname = path.dirname(target)

vm.runInNewContext("module.load(__filename)", ctx, target)

@WolfgangKluge
Copy link
Author

Thanks for answering. For my special case it's ok to not use createScript but a specialized version of require (but I think of using a child process)...
Here's my solution.

function requireCode(code, pathToCode) {
    var vm = require("vm");
    var path = require("path");
    var Module = require("module").Module;

    var filepath = path.resolve(process.cwd(), pathToCode);
    var filename = path.basename(filepath);
    var dirname = path.dirname(filepath);

    var cachedModule = Module._cache[filepath];
    if (cachedModule) {
        return cachedModule.exports;
    }

    var mod = new Module(filepath, module);
    Module._cache[filepath] = mod;

    mod.filename = filepath;
    mod.paths = Module._nodeModulePaths(dirname);

    mod._compile(code, filepath);
    mod.loaded = true;

    return mod.exports;
}

It loads/compiles code as if it were required from pathToCode (relative or absolute). require.extensions is ignored. See https://github.com/WolfgangKluge/node-helpers.

richardlau pushed a commit to ibmruntimes/node that referenced this issue Nov 5, 2015
As per nodejs#2525 a bunch of WGs are renamed from iojs-* to nodejs-*.
Update the WORKING_GROUPS.md to match.

Note specifically iojs-cn and iojs-tw were renamed to nodejs-zh-CN and
nodejs-zh-TW respectively.

Fixes: nodejs/node#3247
PR-URL: nodejs/node#3634
Reviewed-By: James M Snell <jasnell@gmail.com>
richardlau pushed a commit to ibmruntimes/node that referenced this issue Nov 19, 2015
As per nodejs#2525 a bunch of WGs are renamed from iojs-* to nodejs-*.
Update the WORKING_GROUPS.md to match.

Note specifically iojs-cn and iojs-tw were renamed to nodejs-zh-CN and
nodejs-zh-TW respectively.

Fixes: nodejs/node#3247
PR-URL: nodejs/node#3634
Reviewed-By: James M Snell <jasnell@gmail.com>
richardlau pushed a commit to ibmruntimes/node that referenced this issue Nov 19, 2015
As per nodejs#2525 a bunch of WGs are renamed from iojs-* to nodejs-*.
Update the WORKING_GROUPS.md to match.

Note specifically iojs-cn and iojs-tw were renamed to nodejs-zh-CN and
nodejs-zh-TW respectively.

Fixes: nodejs/node#3247
PR-URL: nodejs/node#3634
Reviewed-By: James M Snell <jasnell@gmail.com>
richardlau pushed a commit to ibmruntimes/node that referenced this issue Dec 8, 2015
As per nodejs#2525 a bunch of WGs are renamed from iojs-* to nodejs-*.
Update the WORKING_GROUPS.md to match.

Note specifically iojs-cn and iojs-tw were renamed to nodejs-zh-CN and
nodejs-zh-TW respectively.

Fixes: nodejs/node#3247
PR-URL: nodejs/node#3634
Reviewed-By: James M Snell <jasnell@gmail.com>
richardlau pushed a commit to ibmruntimes/node that referenced this issue Dec 18, 2015
As per nodejs#2525 a bunch of WGs are renamed from iojs-* to nodejs-*.
Update the WORKING_GROUPS.md to match.

Note specifically iojs-cn and iojs-tw were renamed to nodejs-zh-CN and
nodejs-zh-TW respectively.

Fixes: nodejs/node#3247
PR-URL: nodejs/node#3634
Reviewed-By: James M Snell <jasnell@gmail.com>
richardlau pushed a commit to ibmruntimes/node that referenced this issue Jan 11, 2016
As per nodejs#2525 a bunch of WGs are renamed from iojs-* to nodejs-*.
Update the WORKING_GROUPS.md to match.

Note specifically iojs-cn and iojs-tw were renamed to nodejs-zh-CN and
nodejs-zh-TW respectively.

Fixes: nodejs/node#3247
PR-URL: nodejs/node#3634
Reviewed-By: James M Snell <jasnell@gmail.com>
@ghost
Copy link

ghost commented Jul 17, 2017

@WolfgangKluge This worked for me because of a CLI include trying to require from a relative path. Is this still a good way to ensure the correct executable path is used?

Object.assign(tmpGlobal, {
    requireCode: requireCode,
    moduleCode: rendererCode + '(module.exports=global.renderer);',
    projectPath: path.join(project, '.server', 'render-server.js')
});
tmpGlobal.global = tmpGlobal;
renderer = vm.runInNewContext('(requireCode(moduleCode, projectPath));', tmpGlobal);

I've been using this in conjunction with:

process.chdir(path.join(project, '.server'));
module.paths.unshift(path.join(project, 'node_modules'));
require('module').Module._initPaths(); // is this needed?
process.argv = [(process.argv0 = path.join(project, '.server', 'render-service.js'))];

To ensure includes of all types are getting the right relative paths;

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants