使用 ES6 模块导入时 GraalVM 上下文出错

Error in GraalVM Context when using ES6 module imports

我正在尝试将 GraalVM 版本 20.1.0 用于 Java 8 (graalvm-ce-java8-windows-amd64-20.1.0) 到 运行 Java 中的一些 ES6 Java 脚本。我正在使用 Context 这样的:

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();
}

我使用的 JS 文件如下所示:

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

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

export default testFn;

运行 我得到了 非常 无法描述的错误`

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

但是,如果我直接 运行 testFn.js 通过在 Java 代码中将 index.js 替换为 testFn.js 就可以正常工作!如果我删除导入它也能正常工作,所以我假设 ES6 导入有问题。重命名文件以使用 *.mjs 扩展名没有区别。将 allowIO(true) 添加到 Context 配置也不会改变任何内容。

上面的所有代码都是一个 MVCE,您可以根据需要对其进行测试。


如果我也尝试导入一个不存在的文件 (import "./asdasd"),我也会遇到同样的错误,所以可能只是找不到文件。尽管我已经仔细检查过该文件是否存在于它列出的目录中,所以也许这只是巧合。

正如我所见(但并不完全确定),GraalVM 的 Context.eval(Source source) 方法与 JavaScript 的 eval() 函数的工作方式相同。

这可能会导致问题,因为 JS eval 始终将其输入视为脚本,而不是模块,并且静态 import 仅允许在模块内使用。

您可以尝试使用动态 await import('./testFn') 语法,这在 Scripts 中也是允许的(如果 GraalVM 支持它),但不幸的是我不知道它是否会起作用,我也不知道不知道如何将异步资源传递回 Java。

GraalVM中导入时需要指定文件扩展名:

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

请注意,索引文件本身需要具有 .mjs 文件扩展名,而不是 .js 或者 您需要使用 .mimeType("application/javascript+module") 进口工作。但是,您导入的文件不需要特定的文件扩展名。

我已将此识别为一个错误并进行了 bug report here。未来的读者检查 link 以查看此错误是否已修复。