skip to Main Content

A third party dependency returns a javascript code which I would like to execute using vm.runInThisContext.

Unfortunately the javascript module systems missmatch as my script has to be EcmaScriptModule and the generated javascript code can only be generated as CommonJs.

I tried different options of runInThisContext but wasn’t able to make it work.

Here is a simplified version of my problem:

example.mjs

import vm from "node:vm";

// Code to be executed
const code = `
  require("path").resolve("test.mjs");
`;

// Execute code in the current context
vm.runInThisContext(code);
node test.mjs

evalmachine.<anonymous>:2
  require("path").resolve("test.mjs");
  ^

ReferenceError: require is not defined
    at evalmachine.<anonymous>:2:3
    at Script.runInThisContext (node:vm:129:12)
    at Object.runInThisContext (node:vm:307:38)
    at test.mjs:9:4
    at ModuleJob.run (node:internal/modules/esm/module_job:194:25)

Is there any solution for this cross module problem?

2

Answers


  1. Chosen as BEST ANSWER

    I found a solution which works in cjs and esm thanks to the great answer from @sujeet

    const getRequire = async () => {
      if (typeof require !== "undefined") return require;
      const { createRequire } = await import("module");
      return createRequire(import.meta.url);
    };
    
    const code = `
      (require) =>
        require("path").resolve("test.mjs");
    `;
    
    const result = vm.runInThisContext(code)(await getRequire());
    

  2. I don’t think you can use runInThisContext as it will be still tied to your global esm module loader, instead, you can use runInNewContext and provide a separate sandboxed version of the CommonJS module loader.

       
    import vm from 'node:vm';
    import { createRequire } from 'module';
    import { fileURLToPath } from 'url';
    import path from 'path';
    
    const __dirname = path.dirname(fileURLToPath(import.meta.url));
    const require = createRequire(import.meta.url);
    
    const code = `
      const path = require("path");
      path.resolve(__dirname, "test.mjs");
    `;
    
    const sandbox = {
      require,
      __dirname,
      console,
    };
    
    vm.runInNewContext(code, sandbox);
    

    runInNewContext

    working example

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search