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.

Enable dynamically loading npm dependencies

See original GitHub issue

There are cases when a dependency needs to be loaded based on some condition that is evaluated at runtime rather than based on which components are attached to the component tree. Some examples:

  • A polyfill that only needs to be loaded when some specific feature is used with some specific browser.
  • Generic connector functionality related to some specific feature but still not tied to any specific component, e.g. for handling generic DnD.

As long as the file can be used as-is without transpiling, minifying or bundling, then page.addJavaScript("myFile.js") can be used for this purpose (with the file located in /src/main/webapp or corresponding instead of /frontend). Something more sophisticated is needed if the imported file is to be processed by webpack.

The most crude approach is some way that always includes a dependency in generated-flow-imports.js whenever some Java dependency is on the classpath. This could be implemented e.g. by an extra parameter in @JsModule that requires that the module is always included instead of the default that only includes it if it’s referenced. This would mean that the polyfill or DnD connector would always be loaded in all browsers if the corresponding add-on is on the classpath.

This situation can be slightly improved by only including the dependency if the code that needs it is actually referenced in the application. This could work e.g. by allowing @JsModule also on methods. In this situation, the DnD connector would only be included if the application’s UI logic actually runs one of the methods that enable DnD functionality. For the other case, the polyfill would still have to be downloaded by all browsers.

To avoid increasing the production mode bundle size, the conditionally loaded dependency needs to be in a separate chunk. This also means that in addition to the compile-time generation of generated-flow-imports.js, there also needs to be some logic at runtime to determine when some specific chunk should be loaded.

The original @Chunk plan as described in #5537 would only decide which chunks to load at runtime based on on which component classes are currently attached to the UI. This is not enough to avoid loading the polyfill in all browsers. Also, the idea for a fallback chunk (https://github.com/vaadin/flow/issues/5537#issuecomment-486653467) could not be triggered by something like a @JsModule annotated method since the runtime cannot know when the method has been invoked (without ugly hacks such as proxies or bytecode rewriting).

This means that there would have to be an explicit runtime trigger for loading a specific chunk, and also a way for an add-on to indicate that a specific dependency (or set of dependencies) should be loadable as a separate chunk instead of being included in the main chunk.

One potential approach here would be to make things work similarly to Bower mode so that the metadata from the chunking process is read by the runtime to dynamically translate the URL of an imported resource into the corresponding chunk. You would thus somehow declaratively configure a specific dependency to be included in a separate chunk, and then the runtime would take care of translating page.addJavaScript("myFile.js") into loading that particular chunk (unless it’s already loaded).

Rather than separately configuring chunking of resources and then importing by URL, we could reuse the idea from https://github.com/vaadin/flow/issues/5094 to use a class literal as an identifier. In this way, the same mechanism would be usable both during compile time when determining how to write generated-flow-imports.js and at runtime to actually import the resources.

Issue Analytics

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

github_iconTop GitHub Comments

1reaction
Legiothcommented, Sep 23, 2019

I verified that the problem with UserItem is indeed caused by the method reference. I created https://github.com/vaadin/flow/issues/6524 for tracking that defect.

0reactions
Legiothcommented, Oct 17, 2019

Flow 2.1 adds Page.addDynamicImport which will take care of waiting for the import to complete before applying changes. This means that it’s not necessary to do a separate round trip to wait for the result, but instead the button click listener in my example can be like this:

UI.getCurrent().getPage().addDynamicImport("return window.loadDynamic()");
checkStatus();
Read more comments on GitHub >

github_iconTop Results From Across the Web

dynamic-module-loader - npm
The dynamic module loader library allows code to retrieve Node modules from a web server, install them locally and serve them up as...
Read more >
How to dynamically import package.json dependencies based ...
js starts at the parent directory of the current module, and adds /node_modules, and attempts to load the module from that location. Node.js ......
Read more >
Dynamic import from npm package? - Meteor forums
I'm using Meteor 1.5.1. Can we not dynamically load npm packages? Is there something else preventing the loading? Thanks, Dave.
Read more >
Understanding dependency management with Node Modules
JavaScript modules are simply script files which can be loaded into each other to share functionality. One of the main benefits of modules...
Read more >
How to Dynamically Import JavaScript with Import Maps
If you can npm install a package, you should be able to load it via unpkg. Unpkg also includes a browsing option that...
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