【问题标题】:How can I access a JS-exported module object from Java using GraalVM?如何使用 GraalVM 从 Java 访问 JS 导出的模块对象?
【发布时间】:2025-12-02 11:35:01
【问题描述】:

我有一些 JS 代码大致如下:

let ssr = async (arg) => arg || "hello js";
export {ssr as default};

我想从 Java 访问和调用 ssr

我该怎么做?

我一直在尝试这样的事情:

var ctx = Context.newBuilder("js")
                .allowIO(true)
                .allowHostAccess(HostAccess.ALL)
                .build();

        var ssrResource = new String(Server.class.getResourceAsStream("/ssr.mjs").readAllBytes());

        ctx.eval(Source
                .newBuilder("js", ssrResource, "ssr.mjs")
                .build());
        var ssr = ctx.getBindings("js").getMember("ssr");

但这总是返回 null。

【问题讨论】:

  • 非常好的问题。我也在寻找答案。

标签: javascript java graalvm


【解决方案1】:

从一个模块导出的值可以由另一个模块使用import 语法导入。例如,您可以让另一个文件加载您的模块,例如:

// -- some-module-file.mjs
import ssr from 'ssr.mjs'
ssr;

然后通过以下方式执行文件:

File file = loadSomehow("some-module-file.mjs");
Source mainSource = Source.newBuilder("js", file).mimeType("application/javascript+module").build();
Value ssr = context.eval(mainSource);

这里,Value ssr 是您的模块使用export {ssr as default}; 导出的值

【讨论】:

  • 这似乎很有帮助。如果它对我有用,我会尝试并接受答案。谢谢。
【解决方案2】:

以下java代码

import org.graalvm.polyglot.*;

class Main {
    public static void main(String[] args) {
        var ctx = Context.newBuilder("js").allowAllAccess(true).build();
        ctx.eval("js", "let ssr = async (arg) => arg || \"hello js\"");
        var v = ctx.getBindings("js").getMember("ssr");
        System.out.println(v.execute());
    }
}

输出

Promise{[[PromiseStatus]]: "resolved", [[PromiseValue]]: "hello js"}

在 GraalVM CE 20.0.0 上,所以我认为您构建 Source 对象的方式有问题。

【讨论】:

  • 如果您使用我发布的带有exports子句的脚本,它将不起作用。
  • 请注意这是我正在尝试使用的 JS 模块(因此文件扩展名为 mjs)我无法更改 JS 代码。
  • 也许您可以导入模块并将ssr 分配给全局变量以将其传递给绑定?
  • @Renato 啊,相当!错过了,抱歉。