Search code examples
javascriptjavaecmascript-6graalvm

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.


Solution

  • 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.