如何在通过GraalVM从Java程序调用的JavaScript中使用import语句
问题根因
GraalJS默认将eval传入的JS代码识别为传统脚本(Script),而import/export是ES模块(ESM)的专属语法,只有在模块模式下才会被解析,所以直接传带import的代码会报语法错误。
正确实现步骤
第一步:创建Context时开启ES模块相关配置
import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Source; // 初始化Context时添加必要配置 Context context = Context.newBuilder("js") // 开启ES模块支持 .option("js.esm-eval-returns-exports", "true") // 允许访问本地文件系统用于加载模块 .allowIO(true) // 可选:如果要加载npm安装的依赖,配置node_modules的路径 .option("js.commonjs-require", "true") .option("js.commonjs-require-cwd", "/path/to/your/project/root") // 这里填你存放node_modules的目录路径 .build();
第二步:两种执行带import代码的方式
方式1:直接执行ESM代码
不要直接传字符串给eval,先构造Source对象,明确指定这是ES模块:
Source esmSource = Source.newBuilder("js", "import v4 from 'uuid';var o = v4();", "my-esm-script.js") // 标记为ES模块 .mimeType("application/javascript+module") .build(); context.eval(esmSource); // 如果需要获取JS模块导出的变量可参考以下写法 Source exportSource = Source.newBuilder("js", "import v4 from 'uuid';export const uuid = v4();", "export-script.js") .mimeType("application/javascript+module") .build(); var exports = context.eval(exportSource); String uuid = exports.getMember("uuid").asString();
方式2:加载独立的JS模块文件
直接用Source加载文件,不需要手动读取文件流:
// 直接从资源路径加载js模块文件 Source scriptSource = Source.newBuilder("js", Controller.class.getResource("/script.js")) .mimeType("application/javascript+module") .build(); context.eval(scriptSource);
注意事项
- 如果你使用的是npm安装的
uuid包,要确保配置的js.commonjs-require-cwd目录下存在node_modules/uuid文件夹,否则会报模块找不到的错误 - GraalJS版本建议使用22.3及以上的稳定版,旧版本的ESM支持存在较多兼容性问题
内容的提问来源于stack exchange,提问作者Swapnil Pandey
相关产品推荐
相关产品推荐

