【问题标题】:Error in GraalVM Context when using ES6 module imports使用 ES6 模块导入时 GraalVM 上下文中的错误
【发布时间】:2020-06-11 03:02:08
【问题描述】:

我正在尝试使用 GraalVM 版本 20.1.0 for Java 8 (graalvm-ce-java8-windows-amd64-20.1.0) 从 Java 中运行一些 ES6 JavaScript。我像这样使用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;

运行这个我得到 very 无法描述的错误`

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

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

以上所有代码都是一个 MVCE,如果需要,您可以对其进行测试。


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

【问题讨论】:

    标签: javascript java ecmascript-6 graalvm


    【解决方案1】:

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

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

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

    我已将此确定为一个错误并提交了bug report here。未来的读者请检查链接以查看此错误是否已修复。

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 似乎允许动态导入,但不幸的是,这也给出了同样的错误:Promise{[[PromiseStatus]]: "rejected", [[PromiseValue]]: Error: C:\path\to\testFn.js} 好主意,我什至不知道动态导入是 JS 中的一件事!
      • @Charanor 那我想我无能为力了。我对 Graal 不熟悉,对 Java 也不熟悉……
      • 我刚刚意识到,如果我尝试导入一个不存在的文件 (import "./asdasdasd"),我会得到完全相同的错误,所以我想也许只是找不到文件。尽管它肯定存在于它列出的目录中。感谢您的尝试!
      • 解决了!显然,您需要指定要在 GraalVM 中导入的文件的文件扩展名。
      猜你喜欢
      • 2015-12-24
      • 1970-01-01
      • 2017-01-04
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 2015-01-09
      • 2021-12-08
      • 1970-01-01
      相关资源
      最近更新 更多