Skip to content

Conversation

nicolo-ribaudo
Copy link
Member

@nicolo-ribaudo nicolo-ribaudo commented Jun 19, 2025

A goal of the proposal is that implementations can, under some circumstances, easily implement lazy loading of deferred modules (when they know that they don't have syntax errors or transitive async dependencies).

While trying to actually implement an example of that, I found a problem: even though it's not user-exposed, the spec eagerly reads the list of exports in GetModuleNamespace. It requires some non-trivial changes to actually do it lazily, and this PR does it directly in the spec so that implementations are not forced to diverge.

Collection of the list of exports in a module (for the module namespace) is now centralized in GetModuleExportsList, including removal of the "then" key for deferred namespaces.

Closes #69.


cc @dminor. This is probably relevant for the SM implementation. I'll post an example of how to do sync lazy loading in engine262 soon.

Copy link
Collaborator

@guybedford guybedford left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than making this lazy for all module namespaces, would there be any loss here to make it lazy only in the case of deferred module namespaces?

I think we have a really nice strong guarantee today that namespaces are declared upfront, and it would be a shame to "over-proxify" all namespaces when only deferred namespaces need this level of dynamism.

Making it very clear that non deferred namespaces have static semantics and keeping that invariant would be a nice property to maintain I think.

My suggestion would actually be here:

  • Rename GetModuleExportsList to GetLazyModuleExportsList
  • Still set [[Exports]] upfront for normal namespaces
  • In the exotic namespace hooks, use [[Exports]] directly for non-deferred, only calling GetLazyModuleExportsList in the deferred case.

This would make it immediately visible at the implementation level that only deferred namespaces have the dynamism.

A goal of the proposal is that implementations can, under some circumstances,
easily implement lazy loading of deferred modules (when they know that they
don't have syntax errors or transitive async dependencies).

While trying to actually implement an example of that, I found a problem: even though
it's not user-exposed, the spec eagerly reads the list of exports in GetModuleNamespace.
It requires some non-trivial changes to actually do it lazily, and this PR does it directly
in the spec so that implementations are not forced to diverge.

Collection of the list of exports in a module (for the module namespace) is now centralized
in GetModuleExportsList, including removal of the `"then"` key for deferred namespaces.
@nicolo-ribaudo
Copy link
Member Author

@guybedford I updated the PR to still eagerly compute [[Exports]] for non-deferred namespaces.

However, I kept the GetModuleExportsList AO because adding in every single internal method of namesapce objects the "is this lazy? to this, else do that" check was a lot of visual noise that is exactly what that AO dedupes.

Now:

  • ModuleNamespaceCreate doesn't handle [[Exports]] anymore, and that logic has been moved to a new PopulateModuleNamespaceExportsList AO
  • for eager namespaces, GetModuleNamesapce will call ModuleNamespaceCreate and then immediately call PopulateModuleNamespaceExportsList. GetModuleExportsList will assert that [[Exports]] is already populated.
  • for lazy namespaces, GetModuleNamesapce will only call ModuleNamespaceCreate. GetModuleExportsList will then call PopulateModuleNamespaceExportsList if needed.

Preview: https://nicolo-ribaudo.github.io/proposal-defer-import-eval/

@nicolo-ribaudo
Copy link
Member Author

@guybedford I opened #69 as an alternative. I don't actually like making the spec more complex (like this PR does) for something that is not an observable change from ECMAScript code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants