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


317

Was ist der Unterschied zwischen Node module.exportsund ES6 export default? Ich versuche herauszufinden, warum ich den Fehler "__ ist kein Konstruktor" erhalte, wenn ich es export defaultin Node.js 6.2.2 versuche .

Was funktioniert

'use strict'
class SlimShady {
  constructor(options) {
    this._options = options
  }

  sayName() {
    return 'My name is Slim Shady.'
  }
}

// This works
module.exports = SlimShady

Was nicht funktioniert

'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

Antworten:


401

Das Problem ist mit

  • wie ES6-Module in CommonJS emuliert werden
  • wie Sie das Modul importieren

ES6 zu CommonJS

Zum Zeitpunkt des Schreibens unterstützt keine Umgebung ES6-Module nativ. Wenn Sie sie in Node.js verwenden, müssen Sie etwas wie Babel verwenden, um die Module in CommonJS zu konvertieren. Aber wie genau passiert das?

Viele Menschen halten module.exports = ...es für gleichwertig export default ...und exports.foo ...gleichwertig export const foo = .... Das ist allerdings nicht ganz richtig oder zumindest nicht so, wie Babel es macht.

ES6- defaultExporte werden eigentlich auch als Exporte bezeichnet, außer dass dies defaultein "reservierter" Name ist und es eine spezielle Syntaxunterstützung dafür gibt. Schauen wir uns an, wie Babel benannte und Standardexporte kompiliert:

// 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; 

Hier können wir sehen, dass der Standardexport exportsgenau wie eine Eigenschaft für das Objekt wird foo.

Importieren Sie das Modul

Wir können das Modul auf zwei Arten importieren: Entweder mit CommonJS oder mit ES6- importSyntax.

Ihr Problem: Ich glaube, Sie tun so etwas wie:

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

erwartet, dass barder Wert des Standardexports zugewiesen wird. Wie wir im obigen Beispiel sehen können, wird der defaultEigenschaft der Standardexport zugewiesen !

Um auf den Standardexport zugreifen zu können, müssen wir dies tatsächlich tun

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

Wenn wir die ES6-Modulsyntax verwenden, nämlich

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

Babel wird es verwandeln

'use strict';

var _input = require('./input');

var _input2 = _interopRequireDefault(_input);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

console.log(_input2.default);

Sie können sehen, dass jeder Zugriff auf barin Zugriff konvertiert wird .default.


Haben wir kein Duplikat dafür?
Bergi

3
@Bergi: Ich habe nicht nach tbh gesucht (Schande über mich :(). Es gibt sicherlich Fragen zu demselben Problem, die aber anders gestellt wurden. Lassen Sie mich wissen, wenn Sie etwas finden, das passt!
Felix Kling

1
OK, es hat einige Zeit gedauert, diese zu finden, aber Sie können jetzt Ihre neu erworbenen Kräfte verwenden und eine der Optionen auswählen , um ES6 "Standard exportieren" mit CommonJS "erfordern" korrekt zu verwenden. und Kann nicht () Standardexportwert in Babel 6.x als betrogenes Ziel erfordern :-)
Bergi

1
Wie ironisch, dass ich das jetzt tun kann: D
Felix Kling

1
@djKianoosh: Überzeugen Sie sich selbst . Nach der Zuordnung zu module.exports, exportsund module.exportsunterschiedliche Werte haben, so die Zuordnung exports.defaultskeine Wirkung hat (da module.exportsist das, was exportiert wird). Mit anderen Worten, es ist genau das gleiche, als ob Sie es nur getan hätten module.exports = { ... }.
Felix Kling

1

Sie müssen babel in Ihrem Projekt korrekt konfigurieren, um export default und export const foo zu verwenden

npm install --save-dev @babel/plugin-proposal-export-default-from

Fügen Sie dann unten Konfigration in .babelrc hinzu

"plugins": [ 
       "@babel/plugin-proposal-export-default-from"
      ]

1

Felix Kling hat einen großartigen Vergleich dieser beiden durchgeführt, für alle, die sich fragen, wie ein Exportstandard neben benannten Exporten mit module.exports in nodejs ausgeführt werden soll

module.exports = new DAO()
module.exports.initDAO = initDAO // append other functions a named export

// now you have
let DAO = require('_/helpers/DAO');
// DAO by default is exported class or function
DAO.initDAO()

-61

Damit dies funktioniert, muss die Datei, die benötigt oder importiert SlimShadywird, mit Babel mit kompiliert werden 'use strict'.

Ich verwende babel-cli6.18.0 in dem Projekt, in dem dieser Fehler ursprünglich aufgetreten ist.

Ohne 'use strict'ist schlechte Nachrichten Bären

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

"Verwenden Sie streng", bitte

'use strict'
import SlimShady from './slim-shady'
var marshall = new SlimShady()  // all good in the hood

13
Das macht keinen Sinn. Jede Quelle, die importDeklarationen verwendet , ist ein Modul, und diese sind bereits streng. Der eigentliche Unterschied besteht im Erfordernis gegenüber dem Importieren.
Bergi

1
Sinnvoll ist die Verwendung importanstelle von requireund export defaultanstelle von exports.default.
Corey Alix


103
Dies muss die am schlechtesten bewertete Antwort sein, die ich je auf Stackoverflow gesehen habe
Jimi

4
@ Jimi Das liegt daran, dass es die vierthäufigste Antwort auf der gesamten Website ist.
pppery
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.