Status Report: ES6 Modules

2e36436c692b2e5fbc172e9fb7563171?s=47 dherman
November 21, 2013

Status Report: ES6 Modules

My status report (draft complete!) of ES6 modules at the November 2013 TC39 meeting.

2e36436c692b2e5fbc172e9fb7563171?s=128

dherman

November 21, 2013
Tweet

Transcript

  1. Text Dave Herman November 21, 2013 STATUS REPORT: ES6 MODULES

  2. SPEC DRAFT: DONE.

  3. END-TO-END DRAFT DONE linking loading https://github.com/jorendorff/js-loaders

  4. END-TO-END DRAFT DONE • Linking semantics • Loading semantics •

    Execution semantics • Loader API • Dynamic (CommonJS/AMD/Node) compat layer • Bonus: literate implementation starting to pass simple tests
  5. ES6 DRAFT • Updated syntax for new parameterized grammar •

    Static semantics done and edited by Allen
  6. NEXT STEPS • Improve the formatting • Improve spec text

    (with Allen's help) • Integrate into Allen's draft
  7. CLEANUPS: SCRIPTS AND MODULES

  8. 2 > 3 • Three goal non-terminals (Module, Script, ScriptAsync)

    is one too many • Eliminating import from scripts simplifies the loader API — loading is purely about modules • <script async> was a non-starter anyway!
  9. <MODULE> • (Not part of ECMAScript proper, of course) •

    As concise as <script> • More concise than <script async> • Allows inline source • Implicitly strict (as all modules are) • Named <module>: provide source up front • Anonymous <module>: async but force execution
  10. <MODULE> IS A BETTER 1JS • Better global scoping: starts

    in a nested scope • To create persistent globals, must opt in by mutating window/this • Conservation of concepts: no special semantics required for reforming global scope; just a module • A carrot to lead away from blocking scripts • Still accessible to scripts via System.import
  11. LOADER API ! https://gist.github.com/dherman/7568080

  12. CONSTRUCTOR new Loader({ normalize: n, // -> Prom<stringable> locate: l,

    // -> Prom<address> fetch: f, // -> Prom<source> translate: t, // -> Prom<source> instantiate: i // -> Prom<factory?> })
  13. CORE API // Promise<void> l.load(name[, opts]) // Promise<void> l.define(name, src[,

    opts]) // Promise<Module> l.module(src[, opts])
  14. CONVENIENCE API // Promise<Module> l.import(name[, opts])

  15. REGISTRY API l.get(name) // Module? l.set(name, m) // void l.has(name)

    // boolean l.keys() // Iter<string> l.values() // Iter<Module> l.entries() // Iter<[string,Module]>
  16. DECOUPLING REALMS
 FROM LOADERS

  17. SMELLS • Loaders are really about modules, but eval/ evalAsync

    represent scripts • Mixing concerns: scripts vs modules • Mixing concerns: module loading vs sandboxing • Capability hazard:
 new Loader({ intrinsics: otherLoader })
  18. REALMS : GLOBALS : INTRINSICS : EVAL HOOKS • Global

    object & Function/eval are intertwingled • Intrinsics and standard constructors, prototypes are intertwingled • Realm and intrinsics are intertwingled • Everything is deeply intertwingled ;-P
  19. REALM API let loader = new Loader({ realm: r, //

    a Realm object ... });
  20. REALM API let r = new Realm({ ... }); r.global.myGlobal

    = 17; r.eval(...) ! https://gist.github.com/dherman/7568885
  21. SEPARABLE FROM LOADER API • Important, but it's a separate

    concern • Loader defaults to its own realm • Realms: sandboxing, sync script execution • Loaders: async module execution
  22. REALM API let realm = new Realm({ eval: ..., Function:

    ... }, function(builtins) { // global object starts empty // populate with standard builtins mixin(this.global, builtins); });
  23. INDIRECT EVAL let caja = new Realm({ eval: ... });

    ! ! ! caja.eval(` (0,eval)("1 + 2") `);
  24. INDIRECT EVAL let caja = new Realm({ eval: { indirect:

    (s) => { ... } } }); ! caja.eval(` (0,eval)("1 + 2") `);
  25. DIRECT EVAL let caja = new Realm({ eval: ... });

    ! ! ! ! caja.eval(`{ let tmp = f(); eval("tmp") }`);
  26. DIRECT EVAL let caja = new Realm({ eval: { direct:

    { translate: (s) => { ... } } } }); caja.eval(`{ let tmp = f(); eval("tmp") }`);
  27. DIRECT EVAL let caja = new Realm({ eval: ... });

    ! ! ! ! caja.eval(`{ let eval = console.log; eval("hello!") }`);
  28. DIRECT EVAL let caja = new Realm({ eval: { direct:

    { fallback: (f, ...rest) => { ... } } } }); caja.eval(`{ let tmp = f(); eval("tmp") }`);
  29. FUNCTION let caja = new Realm({ Function: ... }); !

    ! ! ! caja.eval(` Function("x", "return x + 1") `);
  30. FUNCTION let caja = new Realm({ Function: (args, body) =>

    { ... } }); ! ! ! ! caja.eval(` Function("x", "return x + 1") `);
  31. FUNCTION* let caja = new Realm({ Function: ... }); !

    ! ! ! caja.eval(` (function*(){}).constructor("x", "return x + 1") `);
  32. FUNCTION* let caja = new Realm({ Function: (args, body, prefix)

    => { ... } }); ! ! ! ! caja.eval(` (function*(){}).constructor("x", "return x + 1") `);
  33. REALM API let r = new Realm({ eval: { indirect,

    direct: { translate, fallback } }, Function });
  34. FUTURE-PROOFING WITH POLYMORPHISM

  35. CROSS-DOMAIN MODULES • Browser loader should allow cross-domain loads •

    ServiceWorker requires cross-domain sources (XHR) and sinks (<img>, <script>, etc.) • Browser's System.define should be a sink • No problem: type of src parameter unconstrained in ES semantics — polymorphism to the rescue • IOW, each loader determines for itself what types are allowed for source
  36. STREAMING MODULES • Might want to support streaming I/O in

    future • Polymorphism allows admitting stream objects for .define and .module in future
  37. 21 NOV 13 RESOLUTIONS • \o/ • Add l.delete(name) •

    Review race conditions and error checking around pending loads • Eliminate Function realm hook (can implement by mutating global.Function and global.Function.prototype.constructor) • {indirect,direct}Eval instead of eval.{indirect,direct} • indirectEval translates source just like directEval.translate • Move Realm callback to named init option • If init option omitted, default to normal global object (all standard builtins, inherit from Object.prototype) • If init option supplied, empty global object with null [[Prototype]]