Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Status Report: ES6 Modules

dherman
November 21, 2013

Status Report: ES6 Modules

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

dherman

November 21, 2013
Tweet

More Decks by dherman

Other Decks in Programming

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]]