-
Notifications
You must be signed in to change notification settings - Fork 72
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
feat(ses,module-source): Dynamic import #2639
Conversation
6b695d3
to
430a7cf
Compare
@@ -41,7 +42,7 @@ scaffold( | |||
); | |||
}, | |||
4, | |||
{ knownFailure: true }, | |||
{ knownArchiveFailure: true }, |
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.
(not a polite way to say you should, just a note)
If you want to assert for both behaviors you could pass an assertion to scaffold that uses testCategoryHint
to decide what to assert instead of this.
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.
Yeah, this is a sign things are getting weedy. We might refactor knowFailure
to be a callback in the future.
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.
🎉
// fails for archives because dynamic import cannot reach modules not | ||
// discovered during archival |
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.
does dynamic require have the same limitation?
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.
Yes.
- Supports dynamic `import` within a `ModuleSource` in conjunction with | ||
a related change in `ses`. |
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.
- Supports dynamic `import` within a `ModuleSource` in conjunction with | |
a related change in `ses`. | |
- Supports dynamic `import` (i.e. `await import(specifier)`) within a `ModuleSource` in conjunction with | |
a related change in `ses`. |
packages/ses/NEWS.md
Outdated
- Adds support for dynamic `import` in conjunction with an update to | ||
`@endo/module-source`. | ||
|
||
- Specifying the long discontinued `mathTaming` or `dateTaming` options logs a |
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.
- Specifying the long discontinued `mathTaming` or `dateTaming` options logs a | |
- Specifying the long-discontinued `mathTaming` or `dateTaming` options logs a |
packages/ses/src/compartment.js
Outdated
/** | ||
* @param {string} fullSpecifier | ||
*/ |
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 is a
fullSpecifier
? - Please add description of function
- Please add return type of function
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.
Answering in comment, but for you:
- A full specifier is a key in the compartment's memo of known modules. When we add support for import attributes (
import ansiSys from 'autoexec.bat' with { type: 'bmp' }
), the full specifier will be a part of the compartment memo key. Functions likecompartment.import
take full specifiers. In Node.js and the web, the full specifier happens to be a fully qualified URL, soimport.meta.url
is the same. In Compartment, the location and full specifier are not necessarily the same. With Compartment Mapper, the full specifier is the specifier you would see in apackage.json
, like./src/compartment.js
(for internal linkage)or
ses` (for external linkage). - an import specifier by contrast is a specifier in the context of the surrounding module’s full specifier, like
./module-instance.js
is an import specifier in./src/compartment.js
that resolves to a full specifier:./src/module-instance.js
. - you will note that a relative specifier like
./foo.js
can has different implications for full specifiers and import specifiers. The./
prefix implies “internal” for a full specifier and full specifiers cannot have..
path components. The./
prefix for an import specifier implies that it should be resolved relative to the importer’s full specifier and..
path components should eat the preceding path component of the full specifier. - I don’t have active recall for the terms Node.js chose to distinguish these.
__options__: true, | ||
__noNamespaceBox__: true, |
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.
Out of curiosity: wtf are these?
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.
Inadequately documented: https://github.com/endojs/endo/blob/master/packages/ses/NEWS.md#v160-2024-07-30
The legacy signature of Compartment
is new Compartment(globals, modules, options)
but I observed that globals
and modules
are both optional, so convinced the stake holders to change this to new Compartment(options)
, with globals
and modules
tucked into the options bag. To make that migration without any practical breaking changes, I introduced __options__
to the options so if you use that all the time now, your code is portable between SES and XS.
The legacy signature of compartment.import()
returned a Promise<{ namespace: ModuleExportsNamespace }>
which has the upside of not running afoul of module namespace objects that happen to export something named then
, but has the downside of being inconsistent with dynamic import. The Module Harmony folks have agreed that the thenable modules hazard is a reality we must acknowledge and can’t paper over going forward. This option elects to opt-in to the current standard proposal behavior and behaves consistently with XS.
__noNamespaceBox__: true, | ||
resolveHook: s => s, | ||
modules: { | ||
'-': { |
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.
Does this have a specific meaning, or could it have been foo
?
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.
It could have been 'foo'
, '.'
, or even ''
.
@@ -171,6 +173,13 @@ export const makeModuleInstance = ( | |||
importMetaHook(moduleSpecifier, importMeta); | |||
} | |||
|
|||
let dynamicImport; |
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 /** @type {x} */
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 if you added a test for CommonJS? Or would that be of low value?
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.
Middling value. We don’t test CJS directly at this layer of abstraction so much as we test the mechanisms for supporting it, which are virtual module sources and compartment.importNow
, neither of which go through the dynamic async import path. The exercise of answering your question convinces me that CJS support is orthogonal to this feature.
430a7cf
to
a38f4a2
Compare
a38f4a2
to
f470696
Compare
Closes: #291
Description
This change adds support for dynamic
import
toses
and@endo/module-source
, such thatimport(x)
in the scope of a module loaded from source (usingModuleSource
in aCompartment
module loading hook).Security Considerations
This change builds on prior work to ensure that dynamic import is facilitated by a hidden lexical name injected by
ses
. The dynamic import mechanism is isolated to the surrounding compartment and specifiers are resolved on the surrounding module.Scaling Considerations
This change introduces a static analysis for the presence of a dynamic
import
in the module source, which it communicates on the module source, even if marshaled through JSON, toses
that it should create animport
closure bound to the calling module’s base specifier. This avoids an allocation for most modules.Documentation Considerations
Only news included. Dynamic import is a language feature that is expected to work in general and documented where JavaScript is documented as a language.
Testing Considerations
This change includes a minimal happy path test that verifies that dynamic import produces a promise that settles on a module namespace object. Note that dynamic import does not box namespaces regardless of the
__noNamespaceBox__
compartment option.Compatibility Considerations
Backward compatible.
Upgrade Considerations
None.