import
ing CommonJS modules?
// CommonJS
// a.js
module.exports = {
foo: 4,
bar: 7,
baz: 12
};
// b.js
var a = require('./a');
console.log(a.bar); // 7
module.exports
is a POJSO, can be anything and changed anytimerequire
is just another regular functionrequire
result is the exported POJSO
// Modules
// a.js
export const number = 4;
export default 7;
// b.js
import florg, { number } from './a.js';
console.log(florg + number); // 11
export
and import
are resolved at module parse timeexport
exposes variable bindingsimport
receives variable bindingsParse time (ES) vs. Runtime (CommonJS)
import
/export
must be top-level:
// valid
import foo from 'foo';
// invalid
if (false) {
import bar from 'bar';
}
// invalid
setTimeout(function () {
export let quz = 14;
});
require
/module.exports
can be anywhere:
// valid
if (Math.random() > 0.1) {
exports.foobar = 7;
} else {
require('rimraf')('/');
}
Where can we use imported variables?
import
ed bindings are determined at parse time and hoisted:
// valid
console.log('this is ok', foo)
import foo from 'foo';
require
is just another function call, so assignment behaves as usual:
// throws an error
console.log('oh no an error', foo); // ReferenceError
const foo = require('./foo');
String literal (ES) vs. any expression (CommonJS)
import
must be a string literal:
// valid
import foo from 'foo';
// invalid
import foo from 'f' + 'oo';
import foo from `template-string`;
import foo from 6;
import foo from {};
require
is a regular function, we can pass anything we want:
require(hasTheLargeHadronColliderDestroyedTheWorldYet ?
'left-pad' :
Math.random() * Date.now() / 2 + 7 + '.js'
);
Variable binding (ES) vs. POJSO (CommonJS)
import
receives a variable binding, export
exposes one:
// foo.js
export let foo = 4;
export function incFoo() { foo += 1; }
// main.js
import { foo, incFoo } from './foo.js';
console.log(foo); // 4
incFoo();
console.log(foo); // 5
// wut.js
var foo = 4;
module.exports = { foo, bar: 7, incFoo, incBar };
function incFoo() { foo += 1; }
function incBar() { module.exports.bar += 1; }
// main.js
var wut = require('./wut');
console.log(wut.foo, wut.bar); // 4, 7
incFoo(); incBar();
console.log(wut.foo, wut.bar); // 4, 8
// Imported bindings are const (read-only)
import foo from './foo.js';
foo = 4; // TypeError: Assignment to constant variable.
// You can forward the exports of another module
export * from 'foo';
// Maybe more on that later
// Proposal: dynamic imports https://github.com/tc39/proposal-dynamic-import
// Implements an `import` function
import(hasTheLargeHadronColliderDestroyedTheWorldYet ?
'left-pad' :
Math.random() * Date.now() / 2 + 7 + '.js'
).then(module => {
// win
});
// Proposal: Loaders https://github.com/whatwg/loader
// Allows customizing the import process on several levels
// (all sorts of urls, transpiling on-the-fly, ...)
// Nothing concrete yet!
// What if there are duplicate names?
export let foo = 4;
export * from 'exports-foo';
// What if multiple modules declare the same identifier?
// mid.js
export * from 'exports-foo';
export * from 'also-exports-foo';
import { foo } from './mid.js'; // SyntaxError
import * as mid from './mid.js'; // no error
console.log(mid.foo); // undefined
Questions?