Skip to content
This repository was archived by the owner on Aug 17, 2022. It is now read-only.

Commit c032d7a

Browse files
committed
Nuance the handling of imports in ESM-integration as suggested in #32
1 parent e405a67 commit c032d7a

File tree

1 file changed

+55
-20
lines changed

1 file changed

+55
-20
lines changed

design/proposals/module-linking/Explainer.md

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,10 @@ WebAssembly.instantiateStreaming(fetch('./a.wasm'), {
833833
where `instantiateStreaming` checks that the module created from `code` exports
834834
a function `six` (and *may* import a function `five`).
835835

836+
Lastly, considering the new exportable types, a module export would naturally
837+
produce a `WebAssembly.Module` object. For an instance export, the JavaScript
838+
correspondence already established by [ESM-integration] is a [Namespace Object].
839+
836840

837841
### ESM-integration
838842

@@ -841,34 +845,60 @@ binaries in all the same places where core module binaries can be loaded today,
841845
branching on the `layer` field in the binary format to determine the kind of
842846
module to decode.
843847

844-
As with the JS API, the main question is how ESM-integration should deal with
845-
single-level imports, instance imports and module imports. Going through these
846-
one at a time:
848+
As with the JS API, the main question for ESM-integration is how to deal with
849+
all imports having a single string as well as the new instance and module
850+
import/export types. Going through these:
851+
852+
For adapter module imports of module type, we need a fundamentally new way to
853+
request that the ESM loader parse or decode a module without *also*
854+
instantiating that module. Recognizing this same need from JavaScript, there is
855+
already a TC39 proposal called [Import Reflection] that adds the ability to
856+
write, in JavaScript:
857+
```js
858+
import Foo from "./foo.wasm" as "wasm-module";
859+
assert(Foo instanceof WebAssembly.Module);
860+
```
861+
With this extension to JavaScript and the ESM loader, an adapter module import
862+
of module type can be treated like an `as "wasm-module"` import by
863+
ESM-integration.
847864

848-
For single-level imports of non-instance type, the natural analogue in an ESM
849-
context is the [default export]. Thus, a single-level non-instance import would
850-
receive whatever the ESM loader says the default value would be.
865+
In all other cases, the (single) string imported by an adapter module import is
866+
first resolved to a [Module Record] using the same process as resolving the
867+
[Module Specifier] of a JavaScript `import`. After this, the handling of the
868+
imported Module Record is determined by the import type:
851869

852870
For imports of instance type, the ESM loader would treat the exports of the
853-
instance type as the imported field names. In the normal two-level
854-
import-an-instance case, this corresponds exactly to existing ESM-integration
855-
behavior. However, for more-deeply nested instances, the ESM loader would need
856-
to recursively extract fields.
857-
858-
Lastly, for imports of modules, ESM-integration would need the ESM loader to
859-
provide a fundamentally new way to parse/decode a module without *also*
860-
instantiating that module. Since this functionality is also useful for JS,
861-
there is already a proposal to add this to ESM called [Import Reflection].
862-
With this proposal, a module import:
871+
instance type as if they were the [Named Imports] of a JavaScript `import`.
872+
Thus, single-level imports of instance type mirror the behavior of core
873+
two-level imports with existing ESM-integration. Since the exports of an
874+
instance type can themselves be instance types, this process must be performed
875+
recursively.
876+
877+
For imports of type `(global externref)` (i.e., an immutable core WebAssembly
878+
global storing a value of type `externref`), the imported Module Record is
879+
first converted to a [Namespace Object] via [`GetModuleNamespace()`] and then
880+
converted to a `(global externref)` as a normal JavaScript value. This allows
881+
the importing adapter module to dynamically access the fields of the
882+
Namespace Object by calling other imported functions (such as `Object.get()`).
883+
In the future, other compatible types (e.g., `handle` Interface Types) could be
884+
included in this case.
885+
886+
Otherwise, if the import cannot accept a Namespace Object (and would error
887+
otherwise), the import is treated like a JavaScript [Imported Default Binding]
888+
and the Module Record is converted to its default value. This allows, for
889+
example, a single level import of a function:
863890
```wasm
864891
(adapter module
865-
(import "./foo.wasm" (module $Foo))
892+
(import "./foo.js" (func (result i32)))
866893
)
867894
```
868-
could be handled by ESM-integration as-if loaded by:
895+
to be satisfied by a JavaScript module via ESM-integration:
869896
```js
870-
import Foo from "./foo.wasm" as "wasm-module";
897+
// foo.js
898+
export default () => 42;
871899
```
900+
Lastly, for exports, ESM-integration would produce the same JavaScript
901+
objects for exports as described above for the JS API.
872902

873903

874904

@@ -880,7 +910,13 @@ import Foo from "./foo.wasm" as "wasm-module";
880910
[Interface Types]: https://github.com/WebAssembly/interface-types
881911

882912
[ESM-integration]: https://github.com/WebAssembly/esm-integration
913+
[Namespace Object]: https://tc39.es/ecma262/multipage/reflection.html#sec-module-namespace-objects
883914
[Import Reflection]: https://github.com/tc39-transfer/proposal-import-reflection
915+
[Module Record]: https://tc39.es/ecma262/#sec-abstract-module-records
916+
[Module Specifier]: https://tc39.es/ecma262/multipage/ecmascript-language-scripts-and-modules.html#prod-ModuleSpecifier
917+
[Named Imports]: https://tc39.es/ecma262/multipage/ecmascript-language-scripts-and-modules.html#prod-NamedImports
918+
[`GetModuleNamespace()`]: https://tc39.es/ecma262/multipage/ecmascript-language-scripts-and-modules.html#sec-getmodulenamespace
919+
[Imported Default Binding]: https://tc39.es/ecma262/multipage/ecmascript-language-scripts-and-modules.html#prod-ImportedDefaultBinding
884920

885921
[Core Concepts]: https://webassembly.github.io/spec/core/intro/overview.html#concepts
886922
[`typeuse`]: https://webassembly.github.io/spec/core/text/modules.html#type-uses
@@ -910,6 +946,5 @@ import Foo from "./foo.wasm" as "wasm-module";
910946

911947
[Figma plugins]: https://www.figma.com/blog/an-update-on-plugin-security/
912948
[Attenuate]: http://cap-lore.com/CapTheory/Patterns/Attenuation.html
913-
[Default Export]: https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export#Description
914949

915950
[Issue-30]: https://github.com/WebAssembly/module-linking/issues/30

0 commit comments

Comments
 (0)