Skip to content
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

Virtual module cannot express "export function x" #70

Open
Jack-Works opened this issue Jul 13, 2022 · 5 comments
Open

Virtual module cannot express "export function x" #70

Jack-Works opened this issue Jul 13, 2022 · 5 comments

Comments

@Jack-Works
Copy link
Member

Current format only allows export var x = function equivalent.

In order to support export function x, we need to add an extra stage on initialization.

initialize(env, context) {
    function x() {}
    env.x = x
    // this runs when VirtualModuleRecord.[[InitializeEnvironment]]
    return () => {
        // this runs when VirtualModuleRecord.[[ExecuteModule]]
    }
}
@patrick-soquet
Copy link
Collaborator

Indeed. The initialization of modules has two steps: InitializeEnvironment and ExecuteModule. The InitializeEnvironment step can be skipped if the module body does not require it.

Both steps are especially meaningful with circular dependencies. Currently virtual modules only have one step, a function which is named initialize, which XS calls as its ExecuteModule step! Oops.

But I would prefer virtual modules to have two explicit hooks: initialize and execute. The initialize hook could be absent, but should be a synchronous function if present. The execute hook should be required but could be an asynchronous function.

@Jack-Works
Copy link
Member Author

The problem with 2 separate hooks they're not in the same lexical context.

const a = module {
    export function a()
    a()
}

Two separate hooks are not friendly to down-level compiling.

const a = {
    initialize(env) {
        function a() {}
        env.a = a
    },
    execute(env) {
        a() // Oops!
    }
}

By this form, it can naturally inherit the lexical context.

initialize(env, context) {
    function a() {}
    env.a = a
    // this runs when VirtualModuleRecord.[[InitializeEnvironment]]
    return () => {
        // this runs when VirtualModuleRecord.[[ExecuteModule]]
        a() // Fine!
    }
}

@kriskowal
Copy link
Member

Would it make sense to have separate protocols for exec and init+exec?

I’m inclined to rename the existing initialize method (back) to execute given the distinctions revealed in this issue.

@devsnek
Copy link
Member

devsnek commented Jul 13, 2022

can't a transpiler just introduce a new unique variable? babel does that all over the place.

@nicolo-ribaudo
Copy link
Member

nicolo-ribaudo commented Jul 13, 2022

@devsnek To have separate initialize/execute methods? It doesn't work if they are called more than once, because they would use the same variable.

Babel compiles to SystemJS (the only module system that can emulate ESM) in a similar way to what's proposed in #70 (comment):

System.register([], function (_export, _context) {
  "use strict";

  function a() {}

  _export("a", a);

  return {
    setters: [],
    execute: function () {
      a();
    }
  };
});

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

No branches or pull requests

5 participants