Single import from modules without default export

# Marius Gundersen (11 years ago)

There are currently three (basic) different ways to imports:

//method A: import the default export as anything the user wants
import defaultWithANewName from "moduleThatExportsUsingDefault";

//method B: import named exports
import {namedExport} from "moduleThatExportsNamedBindings";

//method C: import named exports with rename
import {namedExport as aNewName} from "moduleThatExportsNamedBindings";

The first import (A, without the curly braces) has several advantages:

  • It is two characters shorter than B and several characters shorter than C
  • The name of the imported binding is decided by the user of the module, not the author
  • The user of the module does not need to know the name of the exported binding, set by the author of the module.

Unfortunately it requires that the author of the module uses the default keyword when exporting the binding. This keyword is meant to represent a module with a single export, but this is not restricted. You can therefore use default along with many named exports, or you can have a single named export without using the default keyword. This means that the use of the default keyword is not actually correlated with whether or not the module is a single or multiple export module.

It would be great if we could have single export modules without using the default keyword to mark the exported binding as being special. One way to do this is for method A (import without curly braces) to import the first exported binding from the module, no matter how many named bindings the module has.

This has several advantages:

  • No special syntax or keyword needed for single export modules
  • Users of the module can import the first (only?) binding without needing to know what it is called
  • Single export modules can be extended with multiple named bindings without breaking the import of the module in existing code
  • Legacy code (using AMD or CommonJS) can export a binding without needing to rename the exported object. IOW, they can be easily transpiled.

This assumes the module object (which is available using module theModuleObject from "moduleThatExportsSeveralBindings") is iterable, so the first entry can be accessed.

I therefore want to propose that the default keyword is removed, that only named bindings are allowed when exporting in a module, and that method A imports the first named binding.

Marius Gundersen

# Kevin Smith (11 years ago)
  • The name of the imported binding is decided by the user of the module, not the author
  • The user of the module does not need to know the name of the exported binding, set by the author of the module.

If you seriously want to make these claims, you need to respond to esdiscuss.org/topic/quantifying-default-exports .

I therefore want to propose that the default keyword is removed, that only named bindings are allowed when exporting in a module, and that method A imports the first named binding.

That would mean that simply moving a function definition around within a module would break clients. Ouch!

# Kevin Smith (11 years ago)

It would be great if we could have single export modules without using the default keyword to mark the exported binding as being special. One way to do this is for method A (import without curly braces) to import the first exported binding from the module, no matter how many named bindings the module has.

Better yet, just get rid of the "default" business which (apparently) has no rational basis only adds clutter and confusion to the language core.

# Marius Gundersen (11 years ago)

On Wed, Aug 6, 2014 at 1:02 PM, Kevin Smith <zenparsing at gmail.com> wrote:

  • The name of the imported binding is decided by the user of the module, not the author
  • The user of the module does not need to know the name of the exported binding, set by the author of the module.

If you seriously want to make these claims, you need to respond to esdiscuss.org/topic/quantifying-default-exports .

Sorry, I don't understand what you mean. I'm merely stating that using import a from "module" lets the user of the module decide on the name without needing to know what the author of the imported module named it. I remember you made the claim that:

This argument is unsound, since the user always has to know the API of the source module before use, regardless of whether or not default exports are used.

But there is still the advantage that the user of the module can name it whatever they want with fewer keystrokes.

I therefore want to propose that the default keyword is removed, that only named bindings are allowed when exporting in a module, and that method A imports the first named binding.

That would mean that simply moving a function definition around within a module would break clients. Ouch!

Yes, but only if you swap around the first export with something else. Not sure how large of a problem this is though.

# Marius Gundersen (11 years ago)

On Wed, Aug 6, 2014 at 1:04 PM, Kevin Smith <zenparsing at gmail.com> wrote:

It would be great if we could have single export modules without using the default keyword to mark the exported binding as being special. One way to do this is for method A (import without curly braces) to import the first exported binding from the module, no matter how many named bindings the module has.

Better yet, just get rid of the "default" business which (apparently) has no rational basis only adds clutter and confusion to the language core.

Completely agree, the default should be removed. This is simply a proposal of how we can still have a simple import statement (import $ from "jQuery";) without needing default.

# Kevin Smith (11 years ago)

Completely agree, the default should be removed. This is simply a proposal of how we can still have a simple import statement (import $ from "jQuery";) without needing default.

Ah, I misunderstood - sorry about that. You're basically proposing replacing the "default" mechanism with a "first export" mechanism, then.

# Kevin Smith (11 years ago)

Completely agree, the default should be removed. This is simply a proposal of how we can still have a simple import statement (import $ from "jQuery";) without needing default.

You know, I hate even suggesting any syntax changes at this point, but if we ditched the whole "default" thing, we could probably also get rid of the curlies:

import readFile, writeFile from "node:fs";

And then "* as" would fit in naturally:

import * as FS, readFile from "node:fs";

I think this might result in on overall better user experience. I'll experiment with this from a parsing standpoint.

What would you think about that?

# Marius Gundersen (11 years ago)

On Wed, Aug 6, 2014 at 2:10 PM, Kevin Smith <zenparsing at gmail.com> wrote:

Completely agree, the default should be removed. This is simply a proposal of how we can still have a simple import statement (import $ from "jQuery";) without needing default.

You know, I hate even suggesting any syntax changes at this point, but if we ditched the whole "default" thing, we could probably also get rid of the curlies:

import readFile, writeFile from "node:fs";

And then "* as" would fit in naturally:

import * as FS, readFile from "node:fs";

I'm assuming this import the moduleObject?

I think this might result in on overall better user experience. I'll experiment with this from a parsing standpoint.

What would you think about that?

You still miss the ability to import a single-export module and naming it whatever you want to. How would recreate the following node code in ES6?

//nodeJS
var $ = require("jQuery");

//ES6
import {jQuery as $} from "jQuery";
# Kevin Smith (11 years ago)

And then "* as" would fit in naturally:

import * as FS, readFile from "node:fs";

I'm assuming this import the moduleObject?

Right - "import * as ..." is the new syntax for importing all names into a namespace binding ("FS" in this case), approved at the last TC39 meeting.

You still miss the ability to import a single-export module and naming it whatever you want to. How would recreate the following node code in ES6?

//nodeJS
var $ = require("jQuery");

//ES6
import {jQuery as $} from "jQuery";

"jQuery" would just export "$" as a name (an alias for the "jQuery" variable), like it currently injects "$" into the global object.

# Mark Volkmann (11 years ago)

+1 to Kevin's suggestions.


R. Mark Volkmann Object Computing, Inc.

# Matthew Robb (11 years ago)

What if we just added a way to import based on index:

​import [a,b,c] from "d";​

  • Matthew Robb
# Kevin Smith (11 years ago)

​What if we just added a way to import based on index:

​import [a,b,c] from "d";​

That would be a really big refactoring hazard - reorganization of code within the module could easily break clients.

# Kevin Smith (11 years ago)

You know, I hate even suggesting any syntax changes at this point, but if we ditched the whole "default" thing, we could probably also get rid of the curlies:

import readFile, writeFile from "node:fs";

And then "* as" would fit in naturally:

import * as FS, readFile from "node:fs";

I think this might result in on overall better user experience. I'll experiment with this from a parsing standpoint.

Easy. The changes would be:

ImportDeclaration:
    import ModuleSpecifier ;
    import ImportList FromClause ;

ImportSpecifier:
    ImportedBinding
    IdentifierName as ImportedBinding
    * as ImportedBinding

ExportDeclaration:
    export * FromClause ;
    export ExportList[NoReference] FromClause ;
    export ExportList ;
    export VariableStatement
    export Declaration

// ImportClause removed
// NamedImports removed
// ExportClause removed

Overall, this would a huge simplification for the module syntax and a win for users. All those curlies become tiring on the eyes.

# Kevin Smith (11 years ago)

Under this hypothetical scenario, I would also remove the ability to export bindings with reserved-word names, since the only supporting use case is default exports. The grammar would then be:

ImportDeclaration:
    import ModuleSpecifier ;
    import ImportList FromClause ;

ImportSpecifier:
    ImportedBinding
    Identifier as ImportedBinding
    * as ImportedBinding

ExportDeclaration:
    export * FromClause ;
    export ExportList FromClause ;
    export ExportList ;
    export VariableStatement
    export Declaration

// ImportClause removed
// NamedImports removed
// ExportClause removed

JS currently gets a lot of flak for its reliance on curly braces, and in this case we don't need them.