Home

Awesome

ECMAScript Proposal: export ns from

Stage: N/A - this instead became a "needs consensus" PR, and is merged into ECMA-262!

Champion: Valerie Young

Author: Lee Byron

Reviewers:

Specification: https://tc39.github.io/proposal-export-ns-from/

AST: ESTree.md

Transpiler: See Babel's export-namespace-from plugin.

NOTE: Closely related to the export-default-from proposal.

Problem statement and rationale

The export ___ from "module" statements are a very useful mechanism for building up "package" modules in a declarative way. In the ECMAScript 2015 spec, we can:

These three export-from statements are easy to understand if you understand the semantics of the similar looking import statements.

However there is an import statement which does not have corresponding export-from statement, exporting the ModuleNameSpace object as a named export.

Example:

export * as someIdentifier from "someModule";

Current ECMAScript 2015 Modules:

Import Statement Form[[ModuleRequest]][[ImportName]][[LocalName]]
import v from "mod";"mod""default""v"
import * as ns from "mod";"mod""*""ns"
import {x} from "mod";"mod""x""x"
import {x as v} from "mod";"mod""x""v"
import "mod";
Export Statement Form[[ModuleRequest]][[ImportName]][[LocalName]][[ExportName]]
export var v;nullnull"v""v"
export default function f(){};nullnull"f""default"
export default function(){};nullnull"*default*""default"
export default 42;nullnull"*default*""default"
export {x};nullnull"x""x"
export {x as v};nullnull"x""v"
export {x} from "mod";"mod""x"null"x"
export {x as v} from "mod";"mod""x"null"v"
export * from "mod";"mod""*"nullnull

Proposed addition:

Export Statement Form[[ModuleRequest]][[ImportName]][[LocalName]][[ExportName]]
export * as ns from "mod";"mod""*"null"ns"

Symmetry between import and export

There's a syntactic symmetry between the export-from statements and the import statements they resemble. There is also a semantic symmetry; where import creates a locally named binding, export-from creates an export entry.

As an existing example:

import {v} from "mod";

If then v should be exported, this can be followed by an export. However, if v is unused in the local scope, then it has introduced a name to the local scope unnecessarily.

import {v} from "mod";
export {v};

A single "export from" line directly creates an export entry, and does not alter the local scope. It is symmetric to the similar "import from" statement.

export {v} from "mod";

This presents a developer experience where it is expected that replacing the word import with export will always provide this symmetric behavior.

However, when there is a gap in this symmetry, it can lead to confusing behavior:

"I would like to chime in with use-case evidence. When I began using ES6 (via babel) and discovered imports could be re-exported I assumed the feature set would be symmetrical only to find out quite surprisingly that it was not. I would love to see this spec round out what I believe is a slightly incomplete feature set in ES6."

"I also bumped into this and even thought this was a bug in Babel."

Proposed addition:

The proposed addition follows this same symmetric pattern:

Importing a namespace exotic object (existing):

import * as ns from "mod";

Exporting that name (existing):

import * as ns from "mod";
export {ns};

Symmetric "export from" (proposed):

export * as ns from "mod";

Table showing symmetry

Using the terminology of Table 40 and Table 42 in ECMAScript 2015, the export-from form can be created from the symmetric import form by setting export-from's [[ExportName]] to import's [[LocalName]] and export-from's [[LocalName]] to null.

Statement Form[[ModuleRequest]][[ImportName]][[LocalName]][[ExportName]]
import v from "mod";"mod""default""v"
import {x} from "mod";"mod""x""x"
export {x} from "mod";"mod""x"null"x"
import {x as v} from "mod";"mod""x""v"
export {x as v} from "mod";"mod""x"null"v"
import * as ns from "mod";"mod""*""ns"
<ins>export * as ns from "mod";</ins>"mod""*"null"ns"
export * from "mod";"mod""*"nullnull (many)