使用 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 以查看此错误是否已修复。
我正在尝试将 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 以查看此错误是否已修复。