Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

What is the difference between Node's module.exports 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 
like image 885
Marty Chang Avatar asked Oct 27 '16 21:10

Marty Chang


People also ask

Is module exports ES6?

With the help of ES6, we can create modules in JavaScript. In a module, there can be classes, functions, variables, and objects as well. To make all these available in another file, we can use export and import. The export and import are the keywords used for exporting and importing one or more members in a module.

Is export default ES6?

ES6 provides two ways to export a module from a file: named export and default export. With named exports, one can have multiple named exports per file. Then import the specific exports they want surrounded in braces. The name of imported module has to be the same as the name of the exported module.

What is export default and named export in ES6?

In summary, named exports are used to export multiple values. During the import, it will be possible to use the same name to refer to the exported value. Default exports are used to export a single value from the file. During the import, the name of the value can be different from the exported one.


2 Answers

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 exports.foo ... 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 = exports.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'; console.log(bar); 

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 }; }  console.log(_input2.default); 

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

like image 119
Felix Kling Avatar answered Oct 08 '22 07:10

Felix Kling


Felix Kling did a great comparison on those two, for anyone wondering how to do an export default alongside named exports with module.exports in nodejs

module.exports = new DAO() module.exports.initDAO = initDAO // append other functions as named export  // now you have let DAO = require('_/helpers/DAO'); // DAO by default is exported class or function DAO.initDAO() 
like image 43
moein rahimi Avatar answered Oct 08 '22 07:10

moein rahimi