简体   繁体   中英

Error in GraalVM Context when using ES6 module imports

I'm attempting to use GraalVM version 20.1.0 for Java 8 (graalvm-ce-java8-windows-amd64-20.1.0) to run some ES6 JavaScript from within Java. I'm using Context like this:

try (final Context jsContext = Context.newBuilder("js").allowAllAccess(true).build()) {
    final URL resource = this.getClass().getClassLoader().getResource("index.js");
    final File file = Paths.get(resource.toURI()).toFile();
    final Source source = Source.newBuilder("js", file).mimeType("application/javascript+module").build();
    final Value value = jsContext.eval(source);

    System.out.println(value);
} catch (final IOException e) {
    e.printStackTrace();
} catch (final URISyntaxException e) {
    e.printStackTrace();
}

The JS files I'm using look like this:

// index.js
import testFn from "./testFn";
testFn; // return value to Java

// testFn.js
function testFn() {
    print("Test!");
}

export default testFn;

Running this I get the very undescriptive error `

Exception in thread "main" Error: C:/path/to/testFn.js
    at org.graalvm.polyglot.Context.eval(Context.java:345)
    // This error points to "final Value value = jsContext.eval(source);" in the Java code

However if I run testFn.js directly by replacing index.js with testFn.js in the Java code it works fine, It also works fine if I remove the import. so I assume something is buggy with ES6 imports. Renaming the files to use *.mjs extension makes no difference. Adding allowIO(true) to the Context config also changes nothing.

All of the code above is a MVCE that you can test, if needed.


I get the same error if I try to import a non-existent file as well ( import "./asdasd" ) so perhaps it's just not finding the file. Although I have double-checked that the file exists in the directory it lists so perhaps that's just a coincidence.

You need to specify the file extension when importing in GraalVM :

import testFn from "./testFn.js"; // needs '.js' after file name!
testFn;

Note that the index file itself needs to have either the .mjs file extension, not .js , OR you need to use .mimeType("application/javascript+module") for imports to work. The files you import, however, do not need a specific file extension.

I have identified this as a bug and have made a bug report here . Future readers check the link to see if this bug has been fixed.

As I see (but not perfectly sure), GraalVM's Context.eval(Source source) method works the same way how JavaScript's eval() function does.

That can cause the problem, as JS eval always treats its input as a Script, not as a Module, and static import s are allowed only inside Modules.

You could try to use the dynamic await import('./testFn') syntax instead, which is allowed inside Scripts as well (if GraalVM supports it), but unfortunately I can't tell if it will work, and I don't know how to pass back asynchronous resources to Java.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM