mozilla-spidermonkey / spidermonkey-embedding-examples

Documentation and examples for embedding the SpiderMonkey JavaScript / WebAssembly engine in their applications.
Other
197 stars 34 forks source link

Module-in-repl interop best practices #72

Closed linusmartensson closed 1 year ago

linusmartensson commented 1 year ago

Hey Team Mozilla!

I've been scratching my head recently at the ESM vs CJS gap with respect to REPL-based environments. In an internal project, we're making use of spidermonkey as an interactive scripting environment, and now, as scripts are growing, there's a drive toward modular scripts with reusable components. In short, we have a system executing high-performance code in the background - that can be configured with JS, both through script files, and then interactively via asynchronous REPL command injection once the configuration scripts have run to completion, with all top-level scripts run in the same context and scope as REPL so that they can be accessed later.

I was hoping to be able to directly just integrate ES Modules, but as you can imagine I'm running into all the pitfalls: import vs await import, missing top level await support for JS::Evaluate, JS::Evaluate vs JS::ModuleEvaluate being incompatible for scope, and more.

So, I'm throwing this out as a kind of last-ditch effort before being forced to dump the ESM standard in favor of an aging but easy to integrate CJS require(): What are we supposed to do? Are there any best practices or intended implementation paths for ESM + REPL, or is it a pitfall in the spec?

ptomato commented 1 year ago

The Discourse might be a better place to get answers to that question and find out what other embedders have done.

In GJS, we have the same problem with our REPL. One thing you could do might be to expose a C++ function to JS that works like import(), but blocks the REPL until the import is completed. Or, rewrite your REPL to provide some sort of UI that allows awaiting promises if the REPL expression returns one.