The case for modular Loader.

# John Barton (11 years ago)

The first goal listed for ecmascript modules:

  • Obviate need for globals

(harmony:modules). Ironically, the current proposal for module loading includes a global "System" and possibly "Loader". Worse, it seems like the global System is explicitly expected to be mutated.

Just in case the not-global is goal is controversial, consider the following code snippets:

  1. Using Globals:
    System.import('./myGreatModule');
    
  2. Using Modules:
    import System from './MyCustomLoader';
    System.import('./myGreatModule');
    

Which of these snippets provide a direct path to look for sources of error? In the first one, you need to examine the entire program, and more over you need to carefully consider whether order of execution may alter the outcome. Any code that runs before the snippet, including code delayed by network loading, can change the meaning of System. Such changes could make perfect sense within one set of modules but become an error when those modules are loaded in the same environment as another set.

By contrast, the second snippet directs your attention to a single file.

Let's look into what a custom loader module might look like:

  import {SystemLoader, SystemLoaderHooks} from 'System'; // immutable Loader class
  class Loader extends SystemLoader {
    constructor() {
      super(SystemLoaderHooks);
    }
    // override, delegate, reuse SystemLoader API
    // add non-standard custom functions
  }
  export var System = new Loader();

(Here I have used the capital variable System to emulate the module loader discussion. Personally I think the package should be named 'system' and developers should be using systemLoader.import().)

As a bonus, modular Loader would provide more incentive for developers to adopt modules since they cannot use dynamic loading without also using modules.

The only downside I see to a modular Loader is that simple demo code will require two files. I hope someone will offer a stronger case for our mutable global Loader.

# David Herman (11 years ago)

On Feb 7, 2014, at 8:06 AM, John Barton <johnjbarton at google.com> wrote:

The first goal listed for ecmascript modules:

  • Obviate need for globals

(harmony:modules). Ironically, the current proposal for module loading includes a global "System" and possibly "Loader".

Sorry the goal was unclear. It didn't mean we should never add globals to JS, it meant we should make it so programmers don't need to use globals as a mechanism for code sharing. That doesn't mean there's never any point to adding globals. Even in languages that are born with a module system from day one, they tend to have a standard prelude of globals that are common enough that it would be anti-usable to force programmers to explicit import them.

Worse, it seems like the global System is explicitly expected to be mutated.

This is a red herring; a registry is inherently a shared mutable table, whether you make it accessible via a global variable or via a (globally accessible) module.

import System from './MyCustomLoader';
System.import('./myGreatModule');

This isn't a viable option. The module system needs to be accessible from script code (e.g. HTML element attributes), which can't syntactically import.

# John Barton (11 years ago)

On Mon, Feb 10, 2014 at 8:32 AM, David Herman <dherman at mozilla.com> wrote:

Sorry the goal was unclear. It didn't mean we should never add globals to JS, it meant we should make it so programmers don't need to use globals as a mechanism for code sharing. That doesn't mean there's never any point to adding globals. Even in languages that are born with a module system from day one, they tend to have a standard prelude of globals that are common enough that it would be anti-usable to force programmers to explicit import them.

Thanks, of course I understand and agree that these goals are aspirational and trade-offs are necessary. My argument is that this particular global is anti-usable.

This is a red herring; a registry is inherently a shared mutable table, whether you make it accessible via a global variable or via a (globally accessible) module.

Indeed, however, this herring is only red on one fin: the mutability of System is not limited to the registry and in fact every aspect of the System is mutable. As far as I can tell, a mutation to say normalize or locate is entirely unpredictable without runtime tracing. Unless I am wrong about this, we should not ignore this herring just because of a small botch of red.

This isn't a viable option. The module system needs to be accessible from script code (e.g. HTML element attributes), which can't syntactically import.

Did we give up on <script type='module'>?

# Erik Arvidsson (11 years ago)

I also find the mutation of System.normalize slightly worrisome but I do believe that good programming practice here would mean that you would call the previous version of it after your changes. Mostly like a pre-advice.

{
  let locate = System.locate;
  System.locate = function(...) {
    if (some condition) {
      return your address;
    }
    return locate.call(this, ...);
  };
}

This way it should still be possible to load two sets of libraries without them getting in each others way.

# Erik Arvidsson (11 years ago)

Should have been System.normalize etc.

# David Herman (11 years ago)

On Feb 10, 2014, at 8:55 AM, John Barton <johnjbarton at google.com> wrote:

Indeed, however, this herring is only red on one fin: the mutability of System is not limited to the registry and in fact every aspect of the System is mutable. As far as I can tell, a mutation to say normalize or locate is entirely unpredictable without runtime tracing. Unless I am wrong about this, we should not ignore this herring just because of a small botch of red.

OK, I see what you're saying. I'm just not as concerned because configuring the loader is not something everyone should be doing. It's effectively application-wide configuration.

Did we give up on <script type='module'>?

Didn't give up, no (modulo OT details). But there will always be contexts like <button onclick="..."> that are defined to be a script, not a module.

# John Barton (11 years ago)

On Mon, Feb 10, 2014 at 11:24 AM, Erik Arvidsson <erik.arvidsson at gmail.com>wrote:

This way it should still be possible to load two sets of libraries without them getting in each others way.

Possible, yes, but: We should be thinking in terms of 10s (npm today) or 100s (soon) of libraries, with increasing collision potential. Potential locate() function 'some condition' collisions are order dependent. We are baking in a flaw and offering a partial workaround, yuk. On the other hand we gain what? Enabling Script to import when we want to deprecate script. Marginally fewer lines of code in very few files. Something else? I'd like to know.

If the benefits where larger, the costs would make more sense.