Reconsidering the WebAssembly.Global representation in the ESM Integration
We currently implement a transparent ESM Integration in that the ESM Integration itself adds no extra rules beyond the Wasm JS API when interpreting the imports and exports of a WebAssembly module instance.
As a result, WebAssembly modules may only ever export functions, WebAssembly.Memory, WebAssembly.Table, WebAssembly.Global and WebAssembly.Tag.
I think not having magic in general is the right approach for the ESM integration, but perhaps there is room for one very specific piece of magic here that could allow some new ergonomics:
Instead of exposing exported globals as WebAssembly.Global, what if instead we export globals always as their global value represented in JavaScript, without the WebAssembly.Global wrapper?
This would allow WebAssembly modules to export first-class JS values, with the only restriction in this model then being that mutable globals cannot be mutated on the exports. Note that this restriction is always true in the JS ecosystem for exported values from JS modules, since a module's exports are idomatically immutable from the importer of the module.
The JS API would continue to use the wrapper approach of course.
The spec change here would be quite small, but it could potentially open up some new possibilities for the integration.
Thoughts / feedback welcome further.
@lukewagner pointed out that this might break round-tripping invariants in that passing the exports of one module as the imports of another module would break in the case where a mutable global import is expected as these must always be wrapped in WebAssembly.Global.
One way to solve this "round-tripping" transitivity concern could be to add a symmetrical exception to the ESM Integration on the imports side for mutable WebAssembly.Global to permit mutable globals to be fulfilled by direct values.
This was since landed in https://github.com/WebAssembly/esm-integration/pull/104, with the resolution for round-tripping being the ability to still retain the underlying WebAssembly.Instance instance for direct binding between WebAssembly modules and treating this as purely a JS namespace property.