-
Notifications
You must be signed in to change notification settings - Fork 30.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
loader: allow importing wasm modules #18972
Conversation
const importLookup = {}; | ||
for (const name of imports) | ||
importLookup[name] = Buffer.from(name).toString('base64'); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the name decoding 👆 about?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the names can be paths/urls which don't make very nice identifiers in js
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you post an example, please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahhhh so then it becomes
import * as someBase64Thing from "./add.mjs"
Then you capture that someBase64Thing
namespace object, and then assign it to another object { "./add.mjs": someBase64Thing }
, and then pass it along to get resolved, and then imported into it at
new WebAssembly.Instance(module, reflect.imports)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep
d01894c
to
d774051
Compare
|
||
assert.strictEqual(add(2, 3), 5); | ||
|
||
import('../fixtures/es-modules/add.wasm').then((ns) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm guessing that this dynamic import
will get the module from the cache and thus not instantiate it. This is good, as it checks wasm and cache together, but unfortunately it doesn't check dynamic importing a wasm module.
Perhaps add another import('../fixtures/es-modules/add.wasm?cache-avoider').then(...)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm not checking dynamic instantiation (we know that works), i'm checking the namespace and default exports
lib/internal/loader/Translators.js
Outdated
@@ -90,3 +90,15 @@ translators.set('json', async (url) => { | |||
} | |||
}); | |||
}); | |||
|
|||
translators.set('wasm', async (url) => { | |||
const bytes = await readFileAsync(new URL(url)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other translators have a "debug" line that outputs the action (i.e. "loading wasm ${url}"). I would suggest adding it here.
for (const name of exports) | ||
reflect.exports[name].set(instance.exports[name]); | ||
}, imports); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the error thrown in case of a bad or non-existent wasm
file good enough? Does it include, at least, the path to the problematic module? I would definitely also add a test to verify that an exception is thrown for a bad or non-existent module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
non-existant
-> DefaultResolve won't resolve the file and MODULE_NOT_FOUND
bad
-> WebAssembly.compile rejects and goes up the chain
i'll add another tests for errors
|
||
const importLookup = {}; | ||
for (const name of imports) | ||
importLookup[name] = Buffer.from(name).toString('base64'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't base64 also include the characters +
and /
which are illegal JS identifiers? Also, a base64 string can start with a digit, which is not allowed in JS identifiers.
You can solve this by replacing +
with _
, /
with $
, and adding a letter (e.g. i
) at the beginning of the identifier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ou should also remove the trailing =
signs that are used for padding base64. Or replace them also with $
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i already add $
at the beginning below, but you are right about the other stuff, a huge oversight on my part 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devsnek .toString('hex')
Pardon my ignorance, and this isn't really part of this PR, but why does |
@giltayar we need to delay that final callback until actual execution time, while still already having the reflect pre-evaluated, its a nasty situation (i've tried a few times to consolidate it) |
We should hold off on this until the WASM working group is ready and designed their exact behavior with respect to things like importing JS from WASM and live bindings. CC: @linclark |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs WASM group feedback
Ah, to note: in https://tc39.github.io/ecma262/#sec-source-text-module-records
Is my main concern with respect to loading JS. and lack of liveness from our ESM facades is the other concern. Since WASM would suddenly not be able to have live exports with this. |
627be2a
to
c6a5756
Compare
@bmeck do we know the reason the spec forbids circular dependencies involving both JS and non-JS modules? Is it just because non-JS execution can't be defined, so guaranteeing the "well-behaved-ness" of the execution of the circularly dependent set is hard when it includes non-JS code (even though for wasm at least it seems pretty straightforward since it has similar binding properties to esm itself)? Or was it forbidden so it could be dealt with at a later date? Or was it forbidden because cycles in general are a bad design practice? The lack of commentary in the spec makes it difficult to know the rationale for the limitation. |
@weswigham from irc:
|
c6a5756
to
55dab0b
Compare
Just to update on timing, I added WASM ES modules to the agenda for the March 6 WASM community group call. I also plan to present at the WASM working group face-to-face in April.
The issue where it was introduced is here: tc39/ecma262#916 (in this commit tc39/ecma262@0f36dba). I'll be discussing the WASM ES modules work with Domenic, who introduced it, so can ask him what needs to happen for it to be removed. |
It looks like it's just a matter of the |
Ignoring the obvious desire of for a Oh, also, shouldn't, like, there be a simplified API like this to load wasm in cjs? Or is it expected that once this goes in dynamic import will essentially be that in cjs? |
What is the status here? Should this stay open? |
@BridgeAR blocked because we're waiting to see what happens with wasm integrating with es modules and its a new feature and modules team doesn't want to land new features |
@devsnek Do you think it would better for us to close this until the WebAssembly WG figure out the spec side of things? |
@TimothyGu probably an okay idea |
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
loader
/cc @nodejs/modules