Marty Chang Marty Chang - 1 year ago 744
Node.js Question

module.exports vs. export default in Node.js and ES6

What is the difference between Node's

and ES6's
export default
? I'm trying to figure out why I get the "__ is not a constructor" error when I try to
export default
in Node.js 6.2.2.

What works

'use strict'
class SlimShady {
constructor(options) {
this._options = options

sayName() {
return 'My name is Slim Shady.'

// This works
module.exports = SlimShady

What doesn't work

'use strict'
class SlimShady {
constructor(options) {
this._options = options

sayName() {
return 'My name is Slim Shady.'

// This will cause the "SlimShady is not a constructor" error
// if in another file I try `let marshall = new SlimShady()`
export default SlimShady

Answer Source

The issue is with

  • how ES6 modules are emulated in CommonJS
  • how you import the module

ES6 to CommonJS

At the time of writing this, no environment supports ES6 modules natively. When using them in Node.js you need to use something like Babel to convert the modules to CommonJS. But how exactly does that happen?

Many people consider module.exports = ... to be equivalent to export default ... and ... to be equivalent to export const foo = .... That's not quite true though, or at least not how Babel does it.

ES6 default exports are actually also named exports, except that default is a "reserved" name and there is special syntax support for it. Lets have a look how Babel compiles named and default exports:

// input
export const foo = 42;
export default 21;

// output
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
var foo = = 42;
exports.default = 21; 

Here we can see that the default export becomes a property on the exports object, just like foo.

Import the module

We can import the module in two ways: Either using CommonJS or using ES6 import syntax.

Your issue: I believe you are doing something like:

var bar = require('./input');
new bar();

expecting that bar is assigned the value of the default export. But as we can see in the example above, the default export is assigned to the default property!

So in order to access the default export we actually have to do

var bar = require('./input').default;

If we use ES6 module syntax, namely

import bar from './input';

Babel will transform it to

'use strict';

var _input = require('./input');

var _input2 = _interopRequireDefault(_input);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }


You can see that every access to bar is converted to access .default.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download