Node.js ve ES6'da module.exports vs. export default

Node'un module.exports ile ES6'nın export default arasındaki fark nedir? Node.js 6.2.2deexport default` yapmaya çalıştığımda neden "__ is not a constructor" hatası aldığımı anlamaya çalışıyorum.

Ne işe yarar

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

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

// This works
module.exports = SlimShady

Ne işe yaramıyor?

'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
Çözüm

Sorun şu ki

  • ES6 modüllerinin CommonJS'de nasıl taklit edildiği
  • modülü nasıl içe aktardığınız

ES6'dan CommonJS'e

Bu yazının yazıldığı sırada hiçbir ortam ES6 modüllerini yerel olarak desteklememektedir. Bunları Node.js'de kullanırken modülleri CommonJS'ye dönüştürmek için Babel gibi bir şey kullanmanız gerekir. Ama bu tam olarak nasıl gerçekleşiyor?

Birçok kişi module.exports = ... ifadesini export default ... ve exports.foo ... ifadesini de export const foo = ... ifadesine eşdeğer görmektedir. Ancak bu tam olarak doğru değildir ya da en azından Babel'in yaptığı gibi değildir.

ES6 default dışa aktarımları aslında adlandırılmış dışa aktarımlardır, ancak default bir "reserved" adıdır ve bunun için özel sözdizimi desteği vardır. Babel'in named ve default exportları nasıl derlediğine bir göz atalım:

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

Burada, varsayılan dışa aktarımın foo gibi exports nesnesi üzerinde bir özellik haline geldiğini görebiliriz.

Modülü içe aktarın

Modülü iki şekilde içe aktarabiliriz: Ya CommonJS kullanarak ya da ES6 import sözdizimini kullanarak.

Sorununuz: Sanırım şöyle bir şey yapıyorsunuz:

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

'bar'a varsayılan dışa aktarma değerinin atanmasını bekler. Ancak yukarıdaki örnekte görebileceğimiz gibi, varsayılan dışa aktarma default özelliğine atanmıştır!

Yani varsayılan dışa aktarıma erişmek için aslında yapmamız gereken

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

ES6 modül sözdizimini kullanırsak, yani

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

Babel onu

'use strict';

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

var _input2 = _interopRequireDefault(_input);

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

console.log(_input2.default);

bara yapılan her erişimin.default` erişimine dönüştürüldüğünü görebilirsiniz.

Yorumlar (9)

tl;dr şu anda bunun çalışması için, SlimShady gerektiren veya içe aktaran dosya Babel kullanılarak 'use strict' ile derlenmelidir.

Bu hatayla ilk karşılaştığım projede babel-cli 6.18.0 kullanıyorum.

'use strict' olmadan Kötü Haber Ayıları

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

'use strict', lütfen

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