Module.exports and default export in Node.js and ES6

What is the difference between Node module.exports and ES6 export default ? I am trying to understand why I get the error "__ is not a constructor" when trying 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 does not 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 
+61
ecmascript-6 module
Oct. 27 '16 at 21:58
source share
2 answers

A problem with

  • how ES6 modules are emulated in CommonJS
  • how do you import a module

ES6 to CommonJS

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

Many consider module.exports = ... equivalent to export default ... and exports.foo ... equivalent to export const foo = ... This is not entirely true, although at least not in the way that Babylon does.

ES6 default export is also actually called export, except that default is a "reserved" name and there is special syntax support for it. Let's see how Babel compiles the default name and export:

 // input export const foo = 42; export default 21; // output "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var foo = exports.foo = 42; exports.default = 21; 

Here we see that the default export becomes a property of the exports object, as foo .

Import module

We can import a module in two ways: either using CommonJS, or using the ES6 import syntax.

Your problem: I believe that you are doing something like:

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

expects bar be assigned the default export value. But, as we see in the above example, the default export is assigned to the default property!

So, in order to access the default export, we really need to do

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

If we use the syntax of the ES6 module, namely

 import bar from './input'; console.log(bar); 

Babylon converts it to

 'use strict'; var _input = require('./input'); var _input2 = _interopRequireDefault(_input); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } console.log(_input2.default); 

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

+103
Oct 27 '16 at 22:37
source share

tl; dr right now for this to work, the file that is required or importing SlimShady must be compiled using Babel with 'use strict' .

I am using babel-cli 6.18.0 in a project where I first encountered this error.

Without 'use strict' - bad news>

 var SlimShady = require('./slim-shady'); var marshall = new SlimShady(); // uh, oh... 

'use strict' please

 'use strict' import SlimShady from './slim-shady' var marshall = new SlimShady() // all good in the hood 
-12
Oct. 27 '16 at 22:34
source share



All Articles