question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Make it possible for executeJavaScript snippets to reference values exported by a JS module

See original GitHub issue

When I write JavaScript into a JS module file, I can easily use stuff exported from another module:

import { bar } from "foo";

bar("Hello");

Things get messy if I want to pass a value from the server to bar. Without any framework support, I’d have to create a separate myModule.js module file that imports bar and publishes it somewhere in the global namespace.

import { bar } from "foo";

window.publishedBar = bar;

My Java logic would then need to have @JsModule("./myModule.js") and only then could I do executeJavaScript("publishedBar($0)", "Hello");. Even though this would work, it would require quite much boilerplate.

My assumption is that information about what to import from where would have to be included in the input to webpack (i.e. main.js), which in turn means that it would have to be expressed in a declarative way in the Java code so that the logic that generates main.js could find it.

Since generation of main.js is already based on scanning for @JsModue annotations, we could use additional information in those annotations to generate code in main.js that imports specific parts and stores them somewhere for future use. Based on something like @JsModule(value="foo", imports = {"bar", "baz"}), we could generate main.js like this:

import {bar as generated123, baz as generated321} from "foo";

window.Vaadin.Flow.imports["foo"] = {bar: generated123, baz: generated321};

Based on this, I could do executeJavaScript("Vaadin.Flow.imports['foo'].bar($0)", "Hello"). The Vaadin.Flow.imports syntax is still quite verbose and not very discoverable, but I would at the very least not have to create a separate myModule.js file. In this case, I could have written .foo instead of ['foo'], but that wouldn’t be feasible if importing from e.g. @vaadin/vaadin-grid/someFile.js.

We could also consider always injecting an imports variable into the scope that we set up when evaluating JS expressions from the server, thus simplifying the expression to executeJavaScript("imports['foo'].bar($0), "Hello");.

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:8
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
Legiothcommented, Apr 28, 2021

Based on my latest thinking, we should not not have executeJs at all and thus also not have any problem with referencing JS module exports in such snippets. The reason for that no having executeJs at all is that it’s unfriendly to CSP and has a possibility of causing XSS vulnerabilities if used in the wrong way.

Instead, I’m proposing a new mechanism in https://github.com/vaadin/flow/issues/10759 which would as an added benefit also give natural interop with JS modules.

The original example in this issue with passing a string from the server to a bar function exported from a foo module would then be expressed by defining a Java interface as an overlay over that module, acquiring a proxy instance of that interface from the framework and invoking a method on that proxy.

Interface definition:

@JsExpressionModule("foo")
public interface Foo {
  void bar(String greeting);
}

Usage:

page.getJsInvoker(Foo.class).bar("Hello");

To make more advanced integrations e.g. based on combining multiple modules, one can create an intermediate module with appropriate imports that would then export the combining logic. This intermediate module works in exactly the same way as any other JS module which means that it’s free to make arbitrary imports and exports.

import { bar } from 'foo';
import { bar as anotherBar ) from 'baz';

export function doStuff(value) {
  bar(anotherBar(value));
}
0reactions
samiecommented, Mar 25, 2022

I used a workaround JS like file:

import { MyThing } from './mything.js';
window.MyThing = MyThing;

This works but is rather inconvenient.

Read more comments on GitHub >

github_iconTop Results From Across the Web

JavaScript modules - MDN Web Docs
This guide gives you all you need to get started with JavaScript ... Use of native JavaScript modules is dependent on the import...
Read more >
How to include a JavaScript file in another JavaScript file?
We will get into the depth of import and export of modules in javascript. ... We cannot use an alias name when importing...
Read more >
Can we call the function written in one JavaScript ...
The function could be called as if it was in the same JS File as long as the file ... In 'module.js' you...
Read more >
Using JavaScript Modules and Packages in ...
GraalVM JavaScript is compatible with the latest ECMAScript standard, and can be ... JavaScript can execute JavaScript applications and modules that do not ......
Read more >
Understanding Modules and Import and Export Statements ...
In this tutorial, you will learn what a JavaScript module is and how to use import and export to organize your code. Modular...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found