node.js - nodejs - node js export modules
module.exports vs. export default en Node.js y ES6 (2)
¿Cuál es la diferencia entre
module.exports
de
module.exports
y el
export default
de ES6?
Estoy tratando de averiguar por qué aparece el error "__ no es un constructor" cuando intento
export default
en Node.js 6.2.2.
Que funciona
''use strict''
class SlimShady {
constructor(options) {
this._options = options
}
sayName() {
return ''My name is Slim Shady.''
}
}
// This works
module.exports = SlimShady
Lo que no funciona
''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
- cómo se emulan los módulos ES6 en CommonJS
- cómo importas el módulo
ES6 a CommonJS
Al momento de escribir esto, ningún entorno admite módulos ES6 de forma nativa. Al usarlos en Node.js, debe usar algo como Babel para convertir los módulos a CommonJS. Pero, ¿cómo sucede eso exactamente?
Mucha gente considera que
module.exports = ...
es equivalente al
export default ...
y
export default ...
exports.foo ...
es equivalente a
export const foo = ...
Sin embargo, eso no es del todo cierto, o al menos no cómo lo hace Babel.
Las exportaciones
default
ES6 en realidad también se
denominan
exportaciones, excepto que el
default
es un nombre "reservado" y hay un soporte especial de sintaxis para ello.
Veamos cómo compila Babel las exportaciones con nombre y predeterminadas:
// 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 predeterminada se convierte en una propiedad en el objeto de
exports
, al igual que
foo
.
Importar el módulo
Podemos importar el módulo de dos maneras: usando CommonJS o usando la sintaxis de
import
ES6.
Su problema: creo que está haciendo algo como:
var bar = require(''./input'');
new bar();
esperando que a la
bar
se le asigne el valor de la exportación predeterminada.
Pero como podemos ver en el ejemplo anterior, ¡la exportación predeterminada se asigna a la propiedad
default
!
Entonces, para acceder a la exportación predeterminada, en realidad tenemos que hacer
var bar = require(''./input'').default;
Si usamos la sintaxis del módulo ES6, a saber
import bar from ''./input'';
console.log(bar);
Babel lo transformará a
''use strict'';
var _input = require(''./input'');
var _input2 = _interopRequireDefault(_input);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
console.log(_input2.default);
Puede ver que cada acceso a la
bar
se convierte en acceso
.default
.
tl; dr ahora para que esto funcione, el archivo que requiere o importa
SlimShady
debe compilarse usando Babel con
''use strict''
.
Estoy usando
babel-cli
6.18.0 en el proyecto donde inicialmente encontré este error.
Sin
''use strict''
es Bad News Bears
var SlimShady = require(''./slim-shady'');
var marshall = new SlimShady(); // uh, oh...
''uso estricto'', por favor
''use strict''
import SlimShady from ''./slim-shady''
var marshall = new SlimShady() // all good in the hood