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
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
.
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()
initDAO
needs the object DAO
. Do I have to import the current file itself? Or can I call something like this.DAO()
initDAO
is on the DAO
instance itself, you can use this
to refer to the DAO object.
You need to configure babel correctly in your project to use export default and export const foo
npm install --save-dev @babel/plugin-proposal-export-default-from
then add below configration in .babelrc
"plugins": [
"@babel/plugin-proposal-export-default-from"
]
export someName from './someModules.js';
Success story sharing
module.exports
,exports
andmodule.exports
have different values, so the assignment toexports.defaults
has no effect (becausemodule.exports
is what gets exported). In other words, it's exactly the same as if you only didmodule.exports = { ... }
.ES6
->import library, { a, b, c } from "library";
,commonJS
->const library = require("library"); const { a, b, c } = require("library")
? Just like withReact
, where when using ES6 we can doimport React, { useEffect, useState } from "react";
and when using commonJS we can doconst React = require("react"); const { useEffect, useState } = require("react");
... How can we achieve the same when authoring our own libraries? Thank you!