patriksimek / vm2

Advanced vm/sandbox for Node.js
MIT License
3.86k stars 293 forks source link

Usage with NextJS #526

Closed BrunoQuaresma closed 1 year ago

BrunoQuaresma commented 1 year ago

Hey folks, I'm trying to use vm2 with NextJS and I've been facing a few issues.

  1. The first issue was the missing coffee-script.

    Module not found: Can't resolve 'coffee-script' in '/Users/brunoquaresma/workspace/vm-test/node_modules/vm2/lib'

    I was able to fix that by just installing it with npm i coffee-script.

  2. Now, I'm getting a different error related to the coffee-script install.

    ./node_modules/coffee-script/lib/coffee-script/coffee-script.js
    require.extensions is not supported by webpack. Use a loader instead.
  3. I tried to set coffee-script as an external package using the NextJS config:

    
    /** @type {import('next').NextConfig} */
    const nextConfig = {
    experimental: {
    serverComponentsExternalPackages: ["coffee-script"],
    },
    };

module.exports = nextConfig;

And now, I'm getting a more generic error:
```console
Critical dependency: the request of a dependency is an expression

Import trace for requested module:
./node_modules/vm2/lib/resolver-compat.js
./node_modules/vm2/lib/nodevm.js
./node_modules/vm2/lib/main.js
./node_modules/vm2/index.js
./app/api/script/route.ts

Idk if there is a way to make this work with NextJS but just wondering if someone else faced a similar issue before.

XmiliaH commented 1 year ago

Have you tried without installing coffee-script and setting ignoreWarnings[].message = /Can't resolve 'coffee-script'/ in the webpack config?

BrunoQuaresma commented 1 year ago

@XmiliaH I updated the config to be:

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config) => {
    return {
      ...config,
      ignoreWarnings: [/Can't resolve 'coffee-script'/],
    };
  },
};

module.exports = nextConfig;

And now I'm getting the error:

- warn ./node_modules/vm2/lib/resolver-compat.js
Critical dependency: the request of a dependency is an expression

Import trace for requested module:
./node_modules/vm2/lib/resolver-compat.js
./node_modules/vm2/lib/nodevm.js
./node_modules/vm2/lib/main.js
./node_modules/vm2/index.js
./app/api/script/route.ts
XmiliaH commented 1 year ago

Then try to add the additional module.parser.javascript.commonjsMagicComments=true.

BrunoQuaresma commented 1 year ago

Updated config:

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config) => {
    return {
      ...config,
      ignore warnings: [/Can't resolve 'coffee-script'/],
      module: {
        ...config.module,
        parser: {
          ...config.module.parser,
          javascript: {
            ...config.module.parser.javascript,
            commonjsMagicComments: true,
          },
        },
      },
    };
  },
};

module.exports = nextConfig;

The warning is gone but when I access the route, I get a 404 error. To be sure it is not being caused by nonrelatedvm2 code, I removed it, and I can confirm the API route works normally. So, looks like for some reason, NextJS is not being able to compile the dependencies correctly.

The route code:

import { NextResponse } from "next/server";
import { NodeVM } from "vm2";

export async function GET() {
  console.log("Enter");
  const vm = new NodeVM({
    timeout: 500,
    sandbox: {},
  });
  console.log("Starting");
  const result = vm.run(`return { a: "Bruno: }`);
  console.log("Result");
  return NextResponse.json({ data: result });
}

The logs:

- wait compiling /api/script/route (client and server)...
- event compiled client and server successfully in 1066 ms (395 modules)
- wait compiling /_error (client and server)...

Unfortunately, looks like there is no debug mode for next dev command.

BrunoQuaresma commented 1 year ago

The code that I used to test if it was related to vm2 or not.

import { NextResponse } from "next/server";
import { NodeVM } from "vm2";

export async function GET() {
  console.log("Enter");
  console.log("Starting");
  console.log("Result");
  return NextResponse.json({ data: "a" });
}

The logs:

- event compiled successfully in 242 ms (89 modules)
Enter
Starting
Result
XmiliaH commented 1 year ago

While I cannot tell you why it does not work now. You could try a try-catch block and log the exception. And some notes: NodeVM does not have a timeout option and the return in the sandbox script will not be used.

BrunoQuaresma commented 1 year ago

Even with try-catch there is no error available.

import { NextResponse } from "next/server";
import { VM } from "vm2";

export async function GET() {
  try {
    console.log("Enter");
    const vm = new VM({
      timeout: 500,
      sandbox: {},
    });

    console.log("Starting");
    const result = vm.run(`return { a: "Bruno: }`);

    console.log("Result");

    return NextResponse.json({ data: result });
  } catch (error) {
    console.error(error);
  }
}

I really appreciate your help on this but looks like NextJS is missing something. Ty.

BrunoQuaresma commented 1 year ago

Closing this for now since NextJS does not provide any helpful information on what is causing the error.