ES6 modules (sorry...)

# Axel Rauschmayer (5 years ago)

I apologize for this email, but I still don’t understand the current module design.

Multi-export modules. Modules made sense to me as long as they were maps from names to exported values:

// Module 'library'
export function foo() {
}
export function bar() {
}

// Module 'client1'
import { foo, bar } from 'library';
foo();
bar();

// Module 'client2'
import lib from 'library';
lib.foo();
lib.bar();

Compared to CommonJS, the syntax is nicer and less redundant. Additionally, the curly braces for getting stuff out of a module work, because they look like destructuring. And you get load-time errors if imports don’t match exports.

Single-export modules. Still missing is support for single-export modules, which could be added as follows (the keyword default instead of the asterisk works just as well, in my opinion).

// Module 'MyClass'
export* class {
};

// Module 'client3'
import* MyClass from 'MyClass';

At the moment, it seems to me like multi-export modules and single-export modules are mixed in a way that makes things difficult to understand.

Axel

# Calvin Metcalf (5 years ago)

They curly braces only look like destructuring if you keep the name the same, when imported with a different name it's a slightly different syntax, {oldname as newname} not {oldname: newname}, also as it currently stands

// BAD
import lib from 'library';
lib.foo();
lib.bar();

is not correct, this was the module syntax that was removed so you could have done

// ALSO BAD
module lib from 'library';
lib.foo();
lib.bar();

now from what I understand the only way to do that is

import 'library';
let lib = this.get('library');
# Juan Ignacio Dopazo (5 years ago)

On Monday, June 16, 2014 12:33 AM, Axel Rauschmayer <axel at rauschma.de> wrote:

Single-export modules. Still missing is support for single-export modules, which could be added as follows (the keyword default instead of the asterisk works just as well, in my opinion).

You're being confused by CommonJS. ES6 modules don't have "single-export modules". All modules can have multiple exports. And all modules can have a specially named export called "default" which allows you to skip the curly brackets.

Example:

// foo.js
export default function () // anonymous function
  console.log(42);
}

// bar.js
import answer from 'foo'; // I can give whatever name I want to the default export
answer(); // 42

Juan

# John Barton (5 years ago)

On Sun, Jun 15, 2014 at 8:32 PM, Axel Rauschmayer <axel at rauschma.de> wrote:

I apologize for this email, but I still don’t understand the current module design. ... Single-export modules. Still missing is support for single-export modules, which could be added as follows (the keyword default instead of the asterisk works just as well, in my opinion).

// Module 'MyClass'
export* class {
};

// Module 'client3'
import* MyClass from 'MyClass';

Are these now part of the module design or are you advocating for change? jjb

# C. Scott Ananian (5 years ago)

On Mon, Jun 16, 2014 at 8:53 AM, Calvin Metcalf <calvin.metcalf at gmail.com> wrote:

They curly braces only look like destructuring if you keep the name the same, when imported with a different name it's a slightly different syntax, {oldname as newname} not {oldname: newname}, also as it currently stands

I wish that the authors of the module spec would accept that "object as module" is something JS authors have gotten used to. It's rather nice that we don't have to add another "module" type to our mental model. I understand that the spec authors want to insert some magic mechanisms so that cyclic dependencies "just work", but that shouldn't require us to invalidate our simple mental model for the common case.

Using destructuring syntax for imports would be a good thing. It builds on our existing understanding of JS constructs, instead of adding more gratuitously different things to learn.

Similarly, I like the proposal floated here on es-discuss that reuses the same syntax for "default exports", so that the user doesn't have to know whether the module author did a default export of an single object, or used exports of named functions. The syntax should help the developer by papering over these differences so that destructuring and uses were consistent. Sure, there would be some subtle differences under-the-covers regarding the type of the module object and how the destructuring assignment was implemented, but the syntax shouldn't make the user stumble over these.

# Calvin Metcalf (5 years ago)
# Domenic Denicola (5 years ago)

From: es-discuss <es-discuss-bounces at mozilla.org> on behalf of C. Scott Ananian <ecmascript at cscott.net>

Using destructuring syntax for imports would be a good thing. It builds on our existing understanding of JS constructs, instead of adding more gratuitously different things to learn.

This would be a very bad thing, as long as the current model---where exports are something wildly different from properties of an object, but instead are cross-file with-esque read-only-but-mutable bindings---was maintained. It's extremely important that these bindings look and are manipulated as differently as possible from normal declarations and destructuring of object properties.

# Sam Tobin-Hochstadt (5 years ago)

On Jun 16, 2014 1:06 PM, "Domenic Denicola" <domenic at domenicdenicola.com> wrote:

From: es-discuss <es-discuss-bounces at mozilla.org> on behalf of C. Scott Ananian <ecmascript at cscott.net>

Using destructuring syntax for imports would be a good thing. It builds on our existing understanding of JS constructs, instead of adding more gratuitously different things to learn.

This would be a very bad thing, as long as the current model---where exports are something wildly different from properties of an object, but instead are cross-file with-esque read-only-but-mutable bindings --- was maintained. It's extremely important that these bindings look and are manipulated as differently as possible from normal declarations and destructuring of object properties.

In fact, module instance object properties behave nothing like with, and are just like an object with a getter but no setter. Just as with any other getter, they don't always return the same answer, but that doesn't make them anything like with.

Perhaps you think JS should get rid of setters and getters, if you think they're like with, but you should just say that if so.

# Rick Waldron (5 years ago)

On Mon, Jun 16, 2014 at 1:05 PM, Calvin Metcalf <calvin.metcalf at gmail.com> wrote:

e.g. something like gist.github.com/calvinmetcalf/9252f41bf6e3c8b4add7

re:

let { foo, bar } = import "library";

Ignoring the UnaryExpression ambiguity, what happens here:

// library.js
export const MAX_VALUE = 1023;

// program.js
let { MAX_VALUE } = import "library";
MAX_VALUE = 1;
# Domenic Denicola (5 years ago)

I'm not talking about MIO properties. I'm talking about the bindings created by import declarations.

# Matthew Robb (5 years ago)

I wonder if it would help reduce confusion if the syntax wasn't so similar to destructuring:

import ( foo, bar ) from "library";

or

import < foo, bar > from "library";

  • Matthew Robb
# Calvin Metcalf (5 years ago)

A good question Rick, I sketched that out pretty quickly earlier today. It did take me a while to remember that modules are the ONE place where strings are by reference and not by value...

# C. Scott Ananian (5 years ago)

On Mon, Jun 16, 2014 at 1:06 PM, Domenic Denicola <domenic at domenicdenicola.com> wrote:

From: es-discuss <es-discuss-bounces at mozilla.org> on behalf of C. Scott Ananian <ecmascript at cscott.net>

Using destructuring syntax for imports would be a good thing. It builds on our existing understanding of JS constructs, instead of adding more gratuitously different things to learn. This would be a very bad thing, as long as the current model---where exports are something wildly different from properties of an object, but instead are cross-file with-esque read-only-but-mutable bindings---was maintained. It's extremely important that these bindings look and are manipulated as differently as possible from normal declarations and destructuring of object properties.

I understand why you feel that way, but I still disagree. Even if the bindings are technically mutable, except for during startup in modules with cyclic dependencies (which are thankfully very rare), most programmers will not observe this behavior.

IMO we should optimize for the common case: treat the module import as a destructuring binding. Later, when the JS developer is more advanced and is interested in learning about the corner cases, you can get into the weeds with mutable bindings etc. But don't force the developer to learn things that we'd rather no one use in the first place.

That is, IMHO mutable bindings and modules with cyclic dependencies are members of "the bad parts" of JavaScript. Sure, sometimes there's a valid reason to use them. But for most developers they will be happier sticking with "the good parts" and just thinking of modules as objects with immutable properties. Don't force people to learn about the bad parts just to get work done.

# Jasper St. Pierre (5 years ago)

On Mon, Jun 16, 2014 at 1:22 PM, Rick Waldron <waldron.rick at gmail.com>

wrote:

On Mon, Jun 16, 2014 at 1:05 PM, Calvin Metcalf <calvin.metcalf at gmail.com> wrote:

e.g. something like gist.github.com/calvinmetcalf/9252f41bf6e3c8b4add7

re:

let { foo, bar } = import "library";

Ignoring the UnaryExpression ambiguity, what happens here:

// library.js export const MAX_VALUE = 1023;

// program.js let { MAX_VALUE } = import "library"; MAX_VALUE = 1;

Seems like a straightforward thing to me. "let" creates a local binding for the scope of the file. It shouldn't be anything different from:

function importMyLibrary() {
    let module = import "library";
    return module;
}

let { MAX_VALUE } = importMyLibrary();
MAX_VALUE = 1;

Or:

function importMyLibrary() {
    let module = import "library";
    let MAX_VALUE = module.MAX_VALUE;
    return { MAX_VALUE: MAX_VALUE };
}
# Calvin Metcalf (5 years ago)

Jasper: none of those things are legal in the current spec

# C. Scott Ananian (5 years ago)

On Mon, Jun 16, 2014 at 1:41 PM, C. Scott Ananian <ecmascript at cscott.net> wrote:

That is, IMHO mutable bindings and modules with cyclic dependencies are members of "the bad parts" of JavaScript. Sure, sometimes there's a valid reason to use them. But for most developers they will be happier sticking with "the good parts" and just thinking of modules as objects with immutable properties.

(And, just to be clear: I'm not saying that mutable bindings etc don't belong in the spec. They have valid use cases, and for some users this functionality will be very useful. Handling of cyclic dependencies is arguably one of the improvements the spec makes over the status quo. I'm glad the module spec authors have thought hard about the issue and come up with reasonable solutions. But these features should be recognized as corner cases which don't merit gratuitous deviations from standard syntactic forms in the common case.)

# Rick Waldron (5 years ago)

On Mon, Jun 16, 2014 at 1:40 PM, Calvin Metcalf <calvin.metcalf at gmail.com>

wrote:

A good question Rick, I sketched that out pretty quickly earlier today. It did take me a while to remember that modules are the ONE place where strings are by reference an not by value...

It's more than that—if I specify an export of a specific binding form (in this case const, whether it's a primitive string value or otherwise), then user code shouldn't be able to change the meaning. My const should only be a const, but your design has the surface appearance of permitting that const to become a let binding.

# Rick Waldron (5 years ago)

On Mon, Jun 16, 2014 at 1:41 PM, Jasper St. Pierre <jstpierre at mecheye.net>

wrote:

On Mon, Jun 16, 2014 at 1:22 PM, Rick Waldron <waldron.rick at gmail.com> wrote:

On Mon, Jun 16, 2014 at 1:05 PM, Calvin Metcalf <calvin.metcalf at gmail.com

wrote:

e.g. something like gist.github.com/calvinmetcalf/9252f41bf6e3c8b4add7

re:

let { foo, bar } = import "library";

Ignoring the UnaryExpression ambiguity, what happens here:

// library.js export const MAX_VALUE = 1023;

// program.js let { MAX_VALUE } = import "library"; MAX_VALUE = 1;

Seems like a straightforward thing to me. "let" creates a local binding for the scope of the file. It shouldn't be anything different from:

function importMyLibrary() {
    let module = import "library";
    return module;
}

let { MAX_VALUE } = importMyLibrary();
MAX_VALUE = 1;

Or:

function importMyLibrary() {
    let module = import "library";
    let MAX_VALUE = module.MAX_VALUE;
    return { MAX_VALUE: MAX_VALUE };
}

I think you missed or overlooked the important part: I didn't export a let binding, I exported a const binding.

# Rick Waldron (5 years ago)

A few more thoughts...

On Mon, Jun 16, 2014 at 1:41 PM, Jasper St. Pierre <jstpierre at mecheye.net>

wrote:

On Mon, Jun 16, 2014 at 1:22 PM, Rick Waldron <waldron.rick at gmail.com> wrote:

On Mon, Jun 16, 2014 at 1:05 PM, Calvin Metcalf <calvin.metcalf at gmail.com

wrote:

e.g. something like gist.github.com/calvinmetcalf/9252f41bf6e3c8b4add7

re:

let { foo, bar } = import "library";

Ignoring the UnaryExpression ambiguity, what happens here:

// library.js export const MAX_VALUE = 1023;

// program.js let { MAX_VALUE } = import "library"; MAX_VALUE = 1;

Seems like a straightforward thing to me. "let" creates a local binding for the scope of the file. It shouldn't be anything different from:

function importMyLibrary() {
    let module = import "library";

When does the actual import operation take place? Can I assume that it takes place only after importMyLibrary is called? If so, then import will block while awaiting IO—this is "maybe" ok for non-browser JS runtimes, but not ok for the browser.

    return module;
}

let { MAX_VALUE } = importMyLibrary();
MAX_VALUE = 1;

Or:

function importMyLibrary() {
    let module = import "library";
    let MAX_VALUE = module.MAX_VALUE;
    return { MAX_VALUE: MAX_VALUE };
}

Yes that reassignment works, but it would be a serious flaw (potentially a security hazard) if the language just assumed that was was the desired behaviour.

# Mark Volkmann (5 years ago)

Yes! Don't make it look like destructuring and then say it's nothing like that.

At this point I'd be happy to be able to only get back one thing from an import (no destructure-like syntax) that could be any kind of value, including an object with lots of methods on it like we are used to in Node.js. If I want the properties from such an object to be in variables, I can destructure that object in one more line of code.

# Matthew Robb (5 years ago)

My argument is that you can keep everything the same as it is now but change the syntax to not use curlies and avoid the confusing similarity to destructuring. You could use (a,b,c) or <a,b,c> and it would all

continue working as it does but be less confusing.

  • Matthew Robb
# C. Scott Ananian (5 years ago)

On Mon, Jun 16, 2014 at 2:27 PM, Matthew Robb <matthewwrobb at gmail.com> wrote:

My argument is that you can keep everything the same as it is now but change the syntax to not use curlies and avoid the confusing similarity to destructuring. You could use (a,b,c) or <a,b,c> and it would all continue working as it does but be less confusing.

And (just restating my position), I'm saying that using a new arbitrary punctuation here would be more confusing, since 99% of the time the behavior will be exactly as if it were destructuring (ie, the module isn't going to do any funny mutable binding tricks). If it's a "magic destructuring" at least make it look like a destructuring (ie, no crazy "as" keywords), so that developers don't have to learn where the magic hides unless it is necessary.

# Matthew Robb (5 years ago)
  • Matthew Robb

On Mon, Jun 16, 2014 at 11:42 AM, C. Scott Ananian <ecmascript at cscott.net>

wrote:

On Mon, Jun 16, 2014 at 2:27 PM, Matthew Robb <matthewwrobb at gmail.com> wrote:

My argument is that you can keep everything the same as it is now but change the syntax to not use curlies and avoid the confusing similarity to destructuring. You could use (a,b,c) or <a,b,c> and it would all continue working as it does but be less confusing.

And (just restating my position), I'm saying that using a new arbitrary punctuation here would be more confusing, since 99% of the time the behavior will be exactly as if it were destructuring (ie, the module isn't going to do any funny mutable binding tricks). If it's a "magic destructuring" at least make it look like a destructuring (ie, no crazy "as" keywords), so that developers don't have to learn where the magic hides unless it is necessary. --scott

​So it seems like we agree. So long as ES6 module syntax and semantics are 1:1 with destructuring then label it so. If the previous assertion is true then WHAT is being destructured? Certainly not the default export rather instead it would be the Module instance you are destructuring. This makes import blah from "blah"; no longer make sense. I think this is the core of the confusion and if we want it to be destructuring then I think it needs resolved so that whatever is imported without curlies represents an object that contains the named exports. Unfortunately the only two clean ways to do this would be to have single export ONLY or to have no default export (I could be wrong but I don't think so).

The alternative is to accept that it's NOT destructuring and do whatever needs to be done to reduce the confusion between them. The benefit of this approach is you still get named exports and you still get single export via default exports. This could be achieved by making default import more explicit or by making named imports stand out more from destructuring.

# C. Scott Ananian (5 years ago)

Another alternative is to introduce this funny "binding not destructing" behavior as a first-class language construct, so that one could do:

let o = { f: 1 };
let < f > = o;  // using your angle-bracket syntax for the sake of discussion

o.f = 2;
console.log(f); // prints '2'

let < foo > = import "module"; // same syntax!

Of course this is far too large a change for this late date, etc, etc. But my point is that "modules as objects" works well because it fits well with the rest of the language. If we want f to be an abbreviation for o.f then it would be nice if that binding behavior was part of the base language. --scott

ps. my personal preference is not to introduce new 'binding' syntax, but instead to imagine the values assigned as a result of the destructuring as being somewhat magical proxies which retain their tie to the original module object and reflect changes there. Using proxies as a mental model of the semantics avoids having to muck around with the core notion of variable binding. That is, it really is a let, and it really is ordinary destructuring -- all the magic resides in the particular value returned.

# Frankie Bagnardi (5 years ago)

The other big concern here is that in production, very few people are going to be loading every JavaScript file asynchronously. If there's magic, there needs to be a reasonable way to handle bundling multiple ES6 files together.

The current solution turns it into common.js (or others) and does destructuring. You then use browserify or similar tools to get your bundles. Perhaps a whole tool for ES6 modules will rise, but we have to make sure that the "magic" doesn't mean "only implementable natively". It needs to be something people can use today in ES5 browsers... or else we'll have broken ES6 modules and no one will be able to use "real" ES6 modules.

I'm sure people working on the proposal thought of this, so what was the reasoning?

# Kevin Smith (5 years ago)

The other big concern here is that in production, very few people are going to be loading every JavaScript file asynchronously. If there's magic, there needs to be a reasonable way to handle bundling multiple ES6 files together.

OK, so there are two issues here:

  1. How do you bundle modules together in an all-ES6 world?

There used to be lexical modules, and they made bundling really effortless. I believe that you can still do a fair approximation of bundling without lexical modules, but I haven't created a proof-of-concept yet.

In my opinion, lexical modules should not have been dropped.

  1. How do you bundle modules for use in pre-ES6 worlds?

The short answer is: the way that es6now does. Basically, you give up some support for cyclic dependencies and remotely-updatable exports. But remember, we don't want to limit the ES6 module system to only what can be easily transpiled into ES5. If the most important parts can, then we're all good.

# caridy (5 years ago)

On Jun 16, 2014, at 5:41 PM, Frankie Bagnardi <f.bagnardi at gmail.com> wrote:

The other big concern here is that in production, very few people are going to be loading every JavaScript file asynchronously. If there's magic, there needs to be a reasonable way to handle bundling multiple ES6 files together.

This is completely off target IMO. We want to walk away from bundling, it is tedious, it is ugly, it slows down development, it makes debugging a pain, it makes bucketing almost impossible, it is just a pain in general. Instead, we want to rely on bundling at the lowest level (at the browser level), and that's what SPDY/HTTP2.0 brings to the table, and now that Apple is onboard, I don't see why we should consider bundling a relevant use-case.

# John Barton (5 years ago)

On Mon, Jun 16, 2014 at 3:42 PM, caridy <caridy at gmail.com> wrote:

On Jun 16, 2014, at 5:41 PM, Frankie Bagnardi <f.bagnardi at gmail.com> wrote:

The other big concern here is that in production, very few people are going to be loading every JavaScript file asynchronously. If there's magic, there needs to be a reasonable way to handle bundling multiple ES6 files together.

This is completely off target IMO. We want to walk away from bundling, it is tedious, it is ugly, it slows down development, it makes debugging a pain, it makes bucketing almost impossible, it is just a pain in general. Instead, we want to rely on bundling at the lowest level (at the browser level), and that's what SPDY/HTTP2.0 brings to the table, and now that Apple is onboard, I don't see why we should consider bundling a relevant use-case.

I thought SPDY was, to quote wikipedia, about: "reducing web page en.wikipedia.org/wiki/Web_page load latency en.wikipedia.org/wiki/Latency_(engineering) and improving web

security en.wikipedia.org/wiki/Web_content_security"

How does SPDY help when the issue is lots of small requests ping ponging back and forth between client and server?

(Do we want to wait for SPDY in every browser before we use ES6 modules?)

# caridy (5 years ago)

I thought SPDY was, to quote wikipedia, about: "reducing web page load latency and improving web security" How does SPDY help when the issue is lots of small requests ping ponging back and forth between client and server?

SPDY multiplexes the requests across the same connection, which is essentially a runtime bundling process at the browser level without the hazards of doing it manually, and getting the benefit of the granular caching at the browser level.

(Do we want to wait for SPDY in every browser before we use ES6 modules?)

All major browsers (including safari) support SPDY today. But the point is, we should not consider "bundling" as a prime use-case for modules, because it is not going to be important at all. If people want to do bundling, they will have plenty of options to do so, even with the current module specs.

# Kevin Smith (5 years ago)

All major browsers (including safari) support SPDY today. But the point is, we should not consider "bundling" as a prime use-case for modules, because it is not going to be important at all.

I agree, in principle, but I'm not quite as confident that bundling will have no place on the web. For example, will it really make sense to distribute a third-party library as a collection of individual internal modules? I think it remains to be seen...

# John Barton (5 years ago)

On Mon, Jun 16, 2014 at 4:04 PM, caridy <caridy at gmail.com> wrote:

I thought SPDY was, to quote wikipedia, about: "reducing web page load latency and improving web security" How does SPDY help when the issue is lots of small requests ping ponging back and forth between client and server?

SPDY multiplexes the requests across the same connection, which is essentially a runtime bundling process at the browser level without the hazards of doing it manually, and getting the benefit of the granular caching at the browser level.

Just so I understand, if the dependency tree a depth of 20 and say 300 modules how many round trips from client to server will you need using SPDY? The competition (ES5 prebuilt) uses one.

(Do we want to wait for SPDY in every browser before we use ES6 modules?)

All major browsers (including safari) support SPDY today. But the point is, we should not consider "bundling" as a prime use-case for modules, because it is not going to be important at all.

If people want to do bundling, they will have plenty of options to do so, even with the current module specs.

Could you enumerate these? I thought that there was no option, which is why we are asking.

# Guy Bedford (5 years ago)

The latency problem caused by tree depth can also be solved with a Link prefetch header (when Chrome re-enables this) from a server trace or a simple loader extension that contains a traced dependency cache. Injecting a trace tree is a much simpler and better alternative to bundling as we get the cache benefits Caridy mentioned.

Bundling is only needed in the short to medium-term. I agree native bundling shouldn't be specified to solve a problem that won't exist in due course.

# caridy (5 years ago)

I thought SPDY was, to quote wikipedia, about: "reducing web page load latency and improving web security" How does SPDY help when the issue is lots of small requests ping ponging back and forth between client and server?

SPDY multiplexes the requests across the same connection, which is essentially a runtime bundling process at the browser level without the hazards of doing it manually, and getting the benefit of the granular caching at the browser level.

Just so I understand, if the dependency tree a depth of 20 and say 300 modules how many round trips from client to server will you need using SPDY? The competition (ES5 prebuilt) uses one.

One roundtrip, one cookie is sent, and 300 entries are added into cache. Imagine making a change in one of those 300 modules, today, with bundling, the ES5 prebuilt entry in cache gets stale, and you now have to loaded the whole thing, while using SPDY, only one entry gets stale, so, next time the user visits the app/page, only that piece will have to be loaded over the wire, the rest is just going to rely on the browser's cache. This is a killer feature, specially if you're doing continues deployment.

(Do we want to wait for SPDY in every browser before we use ES6 modules?)

All major browsers (including safari) support SPDY today. But the point is, we should not consider "bundling" as a prime use-case for modules, because it is not going to be important at all.

If people want to do bundling, they will have plenty of options to do so, even with the current module specs.

Could you enumerate these? I thought that there was no option, which is why we are asking.

We have been working on transpilers to transform ES6 modules into dynamic modules that can in fact be used today, but also tomorrow, these dynamic modules (which are covered in the specs today under the loader section) can be bundle up. In other words, you can use the same tools that you use today, e.g.: browserify, and they will work just fine.

# Brian Donovan (5 years ago)

Guy Bedford and I have been discussing a compromise with bundling of “internal” dependencies but leaving “external” dependencies out of the bundle. There are legitimate concerns around exposing a library’s internal module structure to the outside world. For example, Ember is written using ES6 modules but the module structure is not (yet) intended to be part of the API. So it makes sense to scrub those internal modules to act as if they had not existed.

However, if something else in your application depends on RSVP (as Ember does) you should be able to share that dependency with that other e.g. library rather than forcing both libraries to bundle RSVP separately.

The re-write of the ES6 Module Transpiler 1 is being done in such a way to support bundles, and I plan to augment it to support this idea of internal and external modules.

# John Barton (5 years ago)

On Mon, Jun 16, 2014 at 4:49 PM, caridy <caridy at gmail.com> wrote:

I thought SPDY was, to quote wikipedia, about: "reducing web page load latency and improving web security"

How does SPDY help when the issue is lots of small requests ping ponging back and forth between client and server?

SPDY multiplexes the requests across the same connection, which is essentially a runtime bundling process at the browser level without the hazards of doing it manually, and getting the benefit of the granular caching at the browser level.

Just so I understand, if the dependency tree a depth of 20 and say 300 modules how many round trips from client to server will you need using SPDY? The competition (ES5 prebuilt) uses one.

One roundtrip, one cookie is sent, and 300 entries are added into cache. Imagine making a change in one of those 300 modules, today, with bundling, the ES5 prebuilt entry in cache gets stale, and you now have to loaded the whole thing, while using SPDY, only one entry gets stale, so, next time the user visits the app/page, only that piece will have to be loaded over the wire, the rest is just going to rely on the browser's cache. This is a killer feature, specially if you're doing continues deployment.

I agree this does sound great, I just don't see how the browser can know which 300 entries to request until it parses the first entry. If on the other hand you mean the server parses the modules, then it sounds equivalent to bundling.

(Do we want to wait for SPDY in every browser before we use ES6 modules?)

All major browsers (including safari) support SPDY today. But the point is, we should not consider "bundling" as a prime use-case for modules, because it is not going to be important at all.

If people want to do bundling, they will have plenty of options to do so, even with the current module specs.

Could you enumerate these? I thought that there was no option, which is why we are asking.

We have been working on transpilers to transform ES6 modules into dynamic modules that can in fact be used today, but also tomorrow, these dynamic modules (which are covered in the specs today under the loader section) can be bundle up. In other words, you can use the same tools that you use today, e.g.: browserify, and they will work just fine.

Ok, you must mean "TC39 don't have any options, you're on your own".

# John Lenz (5 years ago)

You don't really want 300/3000/30000 modules where you have to "load", "parse", then "request (dependencies)". You really need your dependencies, pre-ordered and pre-loaded (that is bundled) if you want your "empty cache" clients to get a good experience. SPYD is only one piece of a puzzle it isn't a silver bullet for solving module loading. If you want both to have an ideal experience you want bundles of modules and delta compression of your changes. Unfortunately, there isn't a good delta compression solution yet but I have hopes that SDCH might be made more general and standard.

# caridy (5 years ago)

John, there are a couple of solutions at hand that you can apply:

  1. loader provides the right hooks for you to hint at loader what are the modules you need to need to load. which is literally 10 lines of code for an extension of the loader: systemjs/systemjs/blob/master/lib/extension-depCache.js
  2. partial bundling, which Guy Bedford explained in details

You really don't need bundling for the new modules and the new loader.

# Juan Ignacio Dopazo (5 years ago)

There are two options for prefetching dependencies without having to wait for "load" and "parse":

  1. Assume none of your modules use the loader object for loading other modules, parse them during deployment and get the dependency graph.

  2. Use what Guy calls a "tracer" that executes your app during development and stores the dependency graph as it goes, which takes into account calls to loader.import().

As for bundling but you can use loader.define() which takes the name of the module and its source code, ie:

System.define('module1', 'export var answer = 42;');
System.define('module2', 'export var answer = 43;');

There are a couple of issues around this though. The main issue is that you can't call System.define('foo', ...) during foo's import lifecycle. But I think these can be fixed.

Juan

# John Barton (5 years ago)

I guess there is no technical argument that will convince you. Thanks for at least having the discussion, more than we got before.

jjb

# Adam Kircher (5 years ago)

Mutable bindings have valid use cases for object properties as well. My - very late - vote is for modules to use the same destructuring syntax as objects. Just leave out mutable bindings in modules for now. That way both modules and objects use the same syntax and that syntax means the same thing in both cases. Then in ES7+, we introduce the idea of mutable bindings using a new & consistent syntax to both modules and objects.