Description
I’m working on implementing this for Node.js. I have some suggestions for this proposal:
-
For JavaScript module imports, the lack of an assertion type implies
assert { type: 'javascript' }
to match the HTML spec. Thereforeimport './file.js'
is the interchangeable equivalent ofimport './file.js' assert { type: 'javascript' }
. If code contains both, the runtime will behave as if eachimport
statement had been written with the full explicit assertion. -
All non-JavaScript assertion types should be required. So if/when WebAssembly is supported,
assert { type: 'webassembly' }
would be required to import it, regardless of whether or not it’s ultimately decided that WebAssembly is as privileged as JavaScript; and likewise for all other future types.
In other words, within a module graph a resolved URL can have only one valid type. There cannot be two successfully resolved modules for the same URL where the modules have different types, even if one of the types is the implicit javascript
.
This came out of discussing the expected behavior of code like this:
const jsonUrl = 'data:application/json,""'
const results = await Promise.allSettled([
import(jsonUrl),
import(jsonUrl, { assert: { type: 'json' } }),
])
console.log(results.map(result => result.status))
In Chrome, this prints ["rejected", "fulfilled"]
. If you flip the order of the import
statements, it prints ["fulfilled", "rejected"]
. This behavior makes sense to me, and it follows the HTML spec’s statement that “module type is also part of the module map key.”
However, this is in conflict with this proposal’s statement:
Assertions are not part of the module cache key. Implementations are required to return the same module, or an error, regardless of the assertions.
I think that type
, at least, needs to be part of the module cache key. If it weren’t, in the example above one would get ["fulfilled", "fulfilled"]
or ["rejected", "rejected"]
depending on the ordering of the import
statements or a race of which resolved first. This feels like a footgun at best and a bug at worst.
There is a way to have it all, however, where we can avoid race conditions yet still have only one module in the cache per resolved URL: permit only one module to successfully resolve per URL and type
. This is what Chrome is already doing for JSON. We should codify this in the spec, so that all runtimes behave the same way.
All non-JavaScript module types, including WebAssembly, should need an explicit assertion type
so that there would be only one possible successful module imported for a particular URL. Multiple imports of the same URL with different type
s would create a race condition, but as long as the race can have only one winner then the condition doesn’t present a problem. This makes the implementation much simpler, as the runtime doesn’t need to contemplate the possibility of multiple valid modules for the same URL.