Let anon
be the symbol denoting anonymous export.
Assume the following syntaxes:
export default [Expression]; // sets the anonymous export
export [Declaration] // sets a named export
import <[Identifier]> from "module url"; // imports named export
import [Identifier] from "module url"; // imports anonymous export
import "module url" as [Identifier]; // imports module instance object (MIO)
// foo.js
export default "this is default";
// bar.js
import x from "foo.js";
assert(x === "this is default");
import "foo.js" as mio;
assert(mio[anon] === x);
// foo.js
export function aFunction() { };
// bar.js
import <aFunction> from "foo.js";
assert(typeof aFunction === "function");
import x from "foo.js"; // `x` is the MIO by default!
assert(typeof x.aFunction === "function");
import "foo.js" as mio;
assert(mio === x);
assert(mio[anon] === x);
This differs from the current thinking in that import x from "foo.js"
returns the MIO, instead of failing.
// foo.js
export function aFunction() { };
export default "this is default";
// bar.js
import <aFunction> from "foo.js";
assert(typeof aFunction === "function");
import "foo.js" as mio;
assert(mio !== x);
assert(mio[anon] === x);
import x from "foo.js"; // `x` is the anon export we explicitly set, instead of the MIO.
assert(typeof x.aFunction === "undefined");
assert(x === "this is default");
This helps the refactoring hazard identified in https://gist.github.com/domenic/4754483#refactoring-example, allowing libraries to transparently switch from MIOs to objects-or-functions with properties.
E.g., with this proposal, you could have
// libV1.js
export function async() { };
export function sync() { };
// consumer.js
import lib from "libV1.js";
lib.sync();
lib.async();
// libV2.js
export function sync() { };
export function async() { };
function theDefault() {
// User testing has revealed that async is by far the most common operation.
return async();
}
theDefault.sync = sync;
theDefault.async = async;
export default theDefault;
Without Kevin's proposal of a default anonymous export equal to the MIO, with version 1 of the library the consumer would have to be using
import "libV1.js" as lib;
But that would break the moment he switched to version 2 of the library! He'd be required instead to do
import lib from "libV1.js";
This is a notable downside of current proposals vs. Node.js or AMD.
There are very few cases anymore where import ... as
has any utility. Namely, it only matters when you are using a library that:
- Has overriden the default anonymous export
- Is also using named exports
- Does not expose those named exports as properties of the anonymous export
- Has enough properties that consumers usually want to import the module wholesale, instead of piecewise using
import <[Identifier]>
syntax.
I'm on the fence on this one. It's pretty nice, but doesn't feel that clean, y'know?