Most people treat these is interchangeable:
// named import
import { bar } from './foo.js';
bar();
// namespace import
import * as foo from './foo.js';
foo.bar();
Generally, the point here is that foo
is a collection of functions (or other values) — it's not supposed to be thought of as an object. If the author wants bar
to be a method of foo rather than a standalone function, she should write it as such and have a default export foo
with a property bar
. (This isn't just an aesthetic choice — the author has no control over which import form people will use. Assuming people will use the namespace form is bad programming.)
Rollup treats the two forms as equivalent (demo 1, demo 2). If it didn't, it would have to import all of foo
, including the bits that aren't used. (It does deoptimise like this if there's a dynamic lookup on foo
, or if foo
is e.g. exported or passed to a function.) That would suck.
The only time the two forms aren't equivalent is if bar
uses this
. If Rollup can analyse bar
and determine that that's the case, it can a) warn and b) deoptimise. (That doesn't currently happen but it could.) But if bar
looked like this...
function makeAFunction () {
return function () {
console.log('analyse', this);
}
}
export const bar = makeAFunction();
...then analysis gets much harder — in some cases, it would be impossible. So Rollup is faced with a choice between a) deoptimising every time it can't fully analyse a namespace import (lots of false positives, would completely defeat tree-shaking), and b) not being 100% spec-compliant in this case, where the author wrote some bad code. The ideological choice is b, the pragmatic choice is a.
A very very common use case is
import * as m from 'path'; Object.keys(m)
. Does this mean that this will just fail outright in rollup?