Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

SPEC DRAFT: DONE.

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

ES6 DRAFT • Updated syntax for new parameterized grammar • Static semantics done and edited by Allen

Slide 6

Slide 6 text

NEXT STEPS • Improve the formatting • Improve spec text (with Allen's help) • Integrate into Allen's draft

Slide 7

Slide 7 text

CLEANUPS: SCRIPTS AND MODULES

Slide 8

Slide 8 text

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 • was a non-starter anyway!

Slide 9

Slide 9 text

• (Not part of ECMAScript proper, of course) • As concise as • 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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

LOADER API ! https://gist.github.com/dherman/7568080

Slide 12

Slide 12 text

CONSTRUCTOR new Loader({ normalize: n, // -> Prom locate: l, // -> Prom
fetch: f, // -> Prom translate: t, // -> Prom instantiate: i // -> Prom })

Slide 13

Slide 13 text

CORE API // Promise l.load(name[, opts]) // Promise l.define(name, src[, opts]) // Promise l.module(src[, opts])

Slide 14

Slide 14 text

CONVENIENCE API // Promise l.import(name[, opts])

Slide 15

Slide 15 text

REGISTRY API l.get(name) // Module? l.set(name, m) // void l.has(name) // boolean l.keys() // Iter l.values() // Iter l.entries() // Iter<[string,Module]>

Slide 16

Slide 16 text

DECOUPLING REALMS
 FROM LOADERS

Slide 17

Slide 17 text

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 })

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

REALM API let loader = new Loader({ realm: r, // a Realm object ... });

Slide 20

Slide 20 text

REALM API let r = new Realm({ ... }); r.global.myGlobal = 17; r.eval(...) ! https://gist.github.com/dherman/7568885

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

REALM API let realm = new Realm({ eval: ..., Function: ... }, function(builtins) { // global object starts empty // populate with standard builtins mixin(this.global, builtins); });

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

DIRECT EVAL let caja = new Realm({ eval: { direct: { fallback: (f, ...rest) => { ... } } } }); caja.eval(`{ let tmp = f(); eval("tmp") }`);

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

REALM API let r = new Realm({ eval: { indirect, direct: { translate, fallback } }, Function });

Slide 34

Slide 34 text

FUTURE-PROOFING WITH POLYMORPHISM

Slide 35

Slide 35 text

CROSS-DOMAIN MODULES • Browser loader should allow cross-domain loads • ServiceWorker requires cross-domain sources (XHR) and sinks (, , 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

Slide 36

Slide 36 text

STREAMING MODULES • Might want to support streaming I/O in future • Polymorphism allows admitting stream objects for .define and .module in future

Slide 37

Slide 37 text

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