¿Cuál es la diferencia entre Node's module.exports
y ES6's export default
? Estoy tratando de averiguar por qué me sale el error "__ no es un constructor" cuando trato de exportar por defecto
en Node.js 6.2.2.
'use strict'
class SlimShady {
constructor(options) {
this._options = options
}
sayName() {
return 'My name is Slim Shady.'
}
}
// This works
module.exports = SlimShady
'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
El problema es con
En el momento de escribir esto, ningún entorno soporta los módulos ES6 de forma nativa. Cuando se usan en Node.js hay que usar algo como Babel para convertir los módulos a CommonJS. Pero, ¿cómo se hace eso exactamente?
Mucha gente considera que module.exports = ...
es equivalente a export default ...
y que exports.foo ...
es equivalente a export const foo = ...
. Sin embargo, eso no es del todo cierto, o al menos no es como lo hace Babel.
Las exportaciones "por defecto" de ES6 son también exportaciones "con nombre", excepto que "por defecto" es un nombre "reservado" y hay un soporte sintáctico especial para él. Veamos cómo compila Babel las exportaciones con nombre y por defecto:
// 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;
Aquí podemos ver que la exportación por defecto se convierte en una propiedad del objeto exports
, al igual que foo
.
Podemos importar el módulo de dos maneras: O bien utilizando CommonJS o bien utilizando la sintaxis import
de ES6.
Su problema: Creo que usted está haciendo algo como:
var bar = require('./input');
new bar();
esperando que a bar
se le asigne el valor de la exportación por defecto. Pero como podemos ver en el ejemplo anterior, ¡la exportación por defecto se asigna a la propiedad default
!
Así que para acceder a la exportación por defecto tenemos que hacer
var bar = require('./input').default;
Si utilizamos la sintaxis del módulo ES6, es decir
import bar from './input';
console.log(bar);
Babel lo transformará en
'use strict';
var _input = require('./input');
var _input2 = _interopRequireDefault(_input);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
console.log(_input2.default);
Puedes ver que cada acceso a bar
se convierte en acceso .default
.
tl;dr ahora mismo para que esto funcione, el archivo que requiere o importa SlimShady
debe ser compilado usando Babel con 'use strict'
.
Estoy usando babel-cli
6.18.0 en el proyecto donde inicialmente encontré este error.
'use strict'
es Bad News Bearsvar SlimShady = require('./slim-shady');
var marshall = new SlimShady(); // uh, oh...
'use strict'
import SlimShady from './slim-shady'
var marshall = new SlimShady() // all good in the hood