ES6 import directive

# Lorenzo Ferrara (9 years ago)

Dear Ecma International, (and Dear readers, as I don't exactely know who will read this mail)

first of all, I think you do a great job standardising ECMAScript, which I honestly am a great admirer of.

However, there is 1 (only 1) point I can't agree with: the "import" statement. I want to state my opinion on the ECMAScript "import" statement, which is why, as I couldn't find a GitHub issues page, I am writing you this letter. English is not my primary language, so I hope I can explain you my opinion without misconceptions.

Since years there has been a need for a C-style "include" method, which enables "importing" external library code into own code. Finally, with the ES6 standard, the "import" directive has been developed, which is a synchronous and kind of intuitive method for importing external library code.

  1. However, I think the ES6 "import" doesn't conform with the general ECMAScript-style very well, because while ES is a very dynamic scripting language, where you can choose almost everything at runtime, "import" breaks with this style as "import" requires the name of the library to be known at "compile-time", what makes things like import f from (prompt("use old library, for older browsers")?"oldlib.js":"newlib.js"); impossible, which takes away a bit of dynamism from ES. "import" should enable choosing the required libraries at run-time.

  2. imports shouldn't be synchronous, as they require a file to be downloaded (probably over network). As almost any Ajax tutorial states, synchronous file downloads over network are bad practice for various reasons. For example, subsequent code in a file importing a library has to pause execution until the library file has loaded. So, code in a .js file cannot execute until all libraries have loaded, which is a great impact.

imports should be asynchronous. And, as they can either succeed (when they are successfully downloaded and parsed) or fail, they should be tied closely to Promises. Every import should return a Promise that fulfills when the library is ready to use and fails when something went wrong while loading the library.

  1. imports shouldn't have their own syntax since this makes polyfilling harder. there are already some transpilers around, but no recent transpiler can successfully transpile the following:
alert(1);
eval('import x from "mylib"; alert(x)');
alert(2);

In this short piece of code, we can see 2 downsides of current imports:

  • they are synchronous, so alert(2) will not alert 2 until "mylib" has loaded.
  • to execute the code, the execution environment (interpreter) has to fully support the syntax.

Instead of inventing a new syntax for imports, I would use the existing function-style syntax. Like the following:

alert(1);
import("mylib").then(function(mylib){
	alert(mylib.x);
	alert(2);
});
  1. I don't think a library should be a singleton. Rather, libraries should be kind of instantiatable classes. Further more, one should be able to pass arguments to the library when importing a library. But 4) is just my personal opinion based on personal experience. However, I think 1) to 3) are important and should at least be considered.

So, in general, I think introducing imports on a language level is a great idea, however, for implementation easement and for other reasons, I would prefer asynchronous imports using existing syntax instead of synchronous imports with new syntax.

Please correct me if I got something wrong. I'm looking forward to your feedback.

# John Barton (9 years ago)

almost all of your requests are covered by a related imperative loader API, whatwg.github.io/loader/#loader-import This work is not quite complete and thus not well described but your goals will be met with this API.

# kdex (9 years ago)

Reply inline.

On Donnerstag, 7. Januar 2016 17:30:08 CET, Lorenzo Ferrara wrote:

Dear Ecma International, (and Dear readers, as I don't exactely know who will read this mail)

Actually, you're posting to a mailing list whose members may include whoever subscribes to it. But skimming over your text, this seems like the right place to discuss your issues.

  1. "import" requires the name of the library to be known at "compile-time", which takes away a bit of dynamism from ES.

This was a deliberate design choice, since this goes hand in hand with static code analysis. Although slightly outdated, you might want to read this.

If you DO need to dynamically import modules, have a look at the Module Loader API (which introduces a global variable named System, allowing for these kinds of things).

You can read about it here, starting with section 16.5.

  1. imports shouldn't be synchronous

The Module Loader API is actually promise-based, which makes this point moot, I suppose.

  1. imports shouldn't have their own syntax

First of all, I strongly disagree: New syntax can't always be transpiled, since sometimes, there's no way to express it in an earlier version of the language (compare Proxy for instance). This isn't a bad thing; it's actually really important to a lot of us to extend the descriptive power of the language, especially since JS has become a "transpile-to language" for many other languages.

Now, how to load modules isn't actually part of ES6 but has been deferred to the Loader API. You might want to check out SystemJS if you need something close to what browsers will implement soon. Right now, what you need to do when transpiling your code is also transforming it into your module system of choice (AMD, CommonJS, SystemJS, UMD, your custom system, …) before handing it over to environments such as browsers. Babel is very capable of doing this, and it has been for over a year, IIRC.

  1. I don't think a library should be a singleton. Rather, libraries should be kind of instantiatable classes.

What do you mean? Something like:

import jQuery from "jquery";
let jQueryInstantiation = new jQuery();

seems overly verbose to me, at least for the sole purpose of getting an instantiation of jQuery. It seems like this is rather something a person with a Java-esque background would do. There are often times where librarys are really instantiable classes, so what's your point exactly?

# /#!/JoePea (9 years ago)
  1. Import is designed for static analysis at compiled time, but that doesn't limit you from implementing a dynamic module loader, as ​kdex pointed out. You can, for example, still use AMD-style define libraries within ES6 Modules if you wish (though I leave that to you to figure out if you really want to). With tools like Webpack or Browserify, we can use purely ES6 Modules to create bundles for different browsers, then we can simply check at runtime which bundle to request based on the browser.

  2. Imports aren't necessarily synchronous. The style in which you write them is, but what happens behind the scenes can still be asynchronous, with as many dependencies loading in parallel as determined by the module loader's dependency resolution mechanism. Don't worry, someone thought of this already, with performance in mind.

  3. Imports are simply not designed to be used that way. There's other ways to achieve that by using the previously mentioned module loader API (check out SystemJS).

  4. Libraries can export anything, not just singletons. In fact, libraries written in ES6 Modules can export more flexibly than any previous module system (live bindings are amazing, whereby exported things defined outside of your module can become part of the scope of the module that you are importing into, it's really powerful).

You haven't explored the full potential of ES6 Modules yet. Give them a chance, they are really awesome.