graaljs icon indicating copy to clipboard operation
graaljs copied to clipboard

Variables in modules do not end up in the global object/scope, so you can't access them via context.getBindings("js")

Open oobles opened this issue 6 years ago • 5 comments

When embedding JavaScript as part of a Java environment and enabling the modules feature, it is not possible to access any of the variables through the global object/scope from Java.

For example, given a module 'hello.js':

export function hello(x) { print('hello here ' + x); return true; }

And a test file 'test.js':

import { hello } from 'hello.js';

function testing(x) { hello(x); return true; }

If you compile the source using:

File sourceFile = deploymentPath.resolve("test.js").toFile(); Source graalSource = Source.newBuilder(language, sourceFile).mimeType("application/javascript+module").build(); Value result = context.eval(graalSource);

And then attempt get the function:

Value function = context.getBindings(language).getMember("testing");

The function variable will be null. No bindings are available with the following returning an empty set:

Set<String> members = context.getBindings(language).getMemberKeys();

oobles avatar Feb 27 '20 02:02 oobles

As suggested on Slack, this very ugly hack works.

'hello.js':

export function hello(x) {
print('hello here ' + x);
return true;
}

'test.js':

import { hello } from 'hello.js';

export function testing(x) { hello(x); return true; }

'wrap.js':

import * as exports from 'test.js'; exports;

If you compile 'wrap.js' with:

File sourceFile = deploymentPath.resolve(source).toFile();

Source graalSource = Source.newBuilder(language, sourceFile).mimeType("application/javascript+module").build();

You can then put the exports from 'test.js' back into the bindings with:

Value result = context.eval(graalSource); if (result.hasMembers()) {

 Set<String> members = result.getMemberKeys();
 for (String member : members) {
      context.getBindings(language).putMember(member, result.getMember(member));
  }

}

Would rather a cleaner way. :)

oobles avatar Feb 27 '20 02:02 oobles

If I remove the mimeType("application/javascript+module") I get the const & vars populated in the bindings set.

https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.html

FYI - I realise that this is the point of this issue with "modules" and thank you for your workaround :)

I have also checked Value result = context.eval and context.getPolyglotBindings and they are empty also.

warrenc5 avatar Feb 23 '21 22:02 warrenc5

I think it is right that the variables are not in the global scope. This is the meaning of modules. I consider it a mistake that the exported variables and functions are not available in the output object (in the result in your code).

FilipJirsak avatar Aug 08 '21 20:08 FilipJirsak

Probably the new option --js.esm-eval-returns-exports would be helpful. It's documented in the JavaScript Modules section in the docs: https://www.graalvm.org/22.0/reference-manual/js/Modules/

vmutafov avatar Feb 16 '22 19:02 vmutafov