Related proposal: deferred module evaluation
This proposal seems related to work I've been doing on deferred module evaluation: https://github.com/tc39/proposal-defer-import-eval
The flow is largely the same, either return an eagerly evaluated instance, or defer evaluation until it is needed. there are some discussions of "re-instantiated modules" as well. In your case, you want to load the module and instantiate it, or load the module and then use the module object as necessary, without linking or instantiating. One key difference is that you would have an unlinked and uninitialized but compiled webassembly module, whereas the defer import eval proposal does linking.
Perhaps this is something that should be worked on in a more general way? My thinking is that a complete solution would involve exposing the module loading interface and allow customization of the loader itself. For example, an incomplete sketch (don't think the class syntax will actually work, just illustrating)
// user defined loaders
class DeferLoader extends import.Loader {
...
}
class CommonJSLoader extends import.Loader {
...
}
//....
import "x" from "y.js" using DeferLoader;
import "commonjsModule" from "z.js" using CommonJSLoader;
import "z" from "<specifier>" using import.WasmModuleLoader;
etc.
Just thinking what a generic solution might be.
Thanks for the feedback, I hadn't thought of the cross-over so that's very interesting to consider.
I do wonder if loader customization could be seen to be a fully orthogonal problem which applies regardless, since surely importing evaluated modules would be the default under any custom loader scheme?
Specifically, how would a deferred loader would be defined? Loader evaluation hooks can be quite hard to specify without the loader effectively recreating most of the DFS algorithms, but perhaps that would be the way to do it. The risk there is the DFS algorithm invariants being broken in userland / it becoming too hard to construct a userland loader (as we've seen with Jest writing its own loader in Node.js to replicate the linking model internally resulting in lots of user issues).
Random idea - I wonder if a 'deferred' evaluator attribute could make sense? What would it return for the namespace?
I think one of the driving pain points here is that Wasm modules are just easier to instantiate programmatically in many cases, since the interpretation steps do just end up more suited to the use case since the boundaries between Wasm compilations tend to require quite a bit of patching dynamic work especially while these interfaces are evolving so fast towards their final form. Also each compilation has its own specific linking needs, so being able to encapsulate the local toolchain linkage without a global loader having to recreate all the patching information for every single fine-grained Wasm import across a whole application is a huge benefit of this for Wasm. This is pretty much how all Wasm runs today, and I'm not sure we should change that? In contrast, in the ES module system the contract boundary is much simpler and much more respected throughout the ecosystem so global top-down conventions can be applied to the resolver like a single global import map.
In many ways it is quite natural to define attributes returning the naturally specified reflection we have today in WebAssembly.Module and possibly for both JS and Wasm we could even have an import x from 'y' as 'block' in future, effectively being the linked but unexecuted object as specified there. Enabling simple spec layering like this seems a very attractive aspect of this proposal to me. In this way we maintain equal capabilities of linking between JS and Wasm, even if their linking models themselves are slightly asymmetric (as they are anyway due to cycles) with Wasm using more nested programmatic instantiations, but otherwise sharing the simpler JS linking model where necessary. Over time I do think Wasm will unify on the JS linking model as conventions form, but these bridges at least get us there.
The other principle at play is just the one of enabling in JS what will be possible in Wasm - in some ways this proposal can be seen as JS playing catch up with interface types to ensure equal capability of the ability to import an unexecuted module without jumping through fetch hoops.