caoccao / Javet

Javet is Java + V8 (JAVa + V + EighT). It is an awesome way of embedding Node.js and V8 in Java.
https://www.caoccao.com/Javet/
Apache License 2.0
687 stars 65 forks source link

Nodejs ConsoleArgument '--experimental-vm-modules' invalid #377

Open aiselp opened 1 month ago

aiselp commented 1 month ago

I plan to write a loader using the node:vm module to fully control module parsing and loading, but I found that the value of SourceTextModule is undefined, and I tried using the --experimental-vm-modules argument but it didn't work.

val runtimeOption = NodeRuntimeOptions().apply {
            setConsoleArguments(arrayOf("--experimental-vm-modules"))
        }
        V8Host.getNodeInstance().createV8Runtime<NodeRuntime>(runtimeOption).use { runtime ->
            val require = runtime.getNodeModule(NodeModuleModule::class.java).moduleObject
                .invoke<V8Value>(FUNCTION_CREATE_REQUIRE, "/")
            runtime.globalObject.set("require", require)
            val r = runtime.getExecutor(
                """
                 const { SourceTextModule } = require('node:vm');
                 SourceTextModule === undefined
            """.trimIndent()
            ).executeBoolean()
            assert(r == false)
        }

I don't know if the way to pass in the argument is correct.

caoccao commented 1 month ago

Some of the arguments may not work by design. Why do you create a new require?

aiselp commented 1 month ago

Even removing the runtime.globalObject.set("require", require) doesn't work

aiselp commented 1 month ago

In new vm.SourceTextModule(code[, options]), options.initializeImportMeta supports passing in a function to set Import.meta. I need to set Import.meta only through this method

caoccao commented 1 month ago

ESM is handled by Javet module resolver. I don't think the whole thing would work.

aiselp commented 1 month ago

I think this is feasible

const { Script, constants } = require('node:vm');
const script = new Script(
  'import("./module.mjs")',
  { importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER });
script.runInNewContext()

In this code, import() is completely handled by nodejs. If module.mjs contains the import keyword, its parsing is also handled by nodejs.

aiselp commented 1 month ago

This shows that the nodejs esm parser is still valid

caoccao commented 1 month ago

import() is completely implemented in JS. It has nothing to do with ESM. It's called dynamic import.