module.exports เทียบกับค่าเริ่มต้นการส่งออกใน Node.js และ ES6


317

ความแตกต่างระหว่างโหนดmodule.exportsและ ES6 คือexport defaultอะไร? ฉันพยายามคิดว่าทำไมฉันถึงได้รับข้อผิดพลาด "__ ไม่ใช่ตัวสร้าง" เมื่อฉันพยายามexport defaultใน 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

คำตอบ:


401

ปัญหาอยู่กับ

  • วิธีการจำลองโมดูล ES6 ใน CommonJS
  • วิธีที่คุณนำเข้าโมดูล

ES6 ถึง CommonJS

ในขณะที่เขียนสิ่งนี้ไม่มีสภาพแวดล้อมรองรับโมดูล ES6 เมื่อใช้พวกมันใน Node.js คุณต้องใช้บางอย่างเช่น Babel เพื่อแปลงโมดูลเป็น CommonJS แต่มันเกิดขึ้นได้อย่างไร

หลายคนพิจารณาmodule.exports = ...ที่จะเทียบเท่ากับexport default ...และที่จะเทียบเท่ากับexports.foo ... export const foo = ...แม้ว่าจะไม่เป็นความจริง แต่อย่างน้อยหรือไม่ใช่วิธีที่บาเบลทำ

การdefaultส่งออกES6 นั้นจริง ๆ แล้วชื่อการส่งออกยกเว้นว่าdefaultเป็นชื่อ "สงวน" และมีการสนับสนุนไวยากรณ์พิเศษสำหรับมัน มาดูกันว่า Babel รวบรวมชื่อและการส่งออกเริ่มต้นอย่างไร:

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

ที่นี่เราจะเห็นได้ว่าการส่งออกเริ่มต้นจะกลายเป็นสถานที่ให้บริการเกี่ยวกับการที่วัตถุเช่นเดียวกับexportsfoo

นำเข้าโมดูล

เราสามารถนำเข้าโมดูลได้สองวิธี: อาจใช้ CommonJS หรือใช้importไวยากรณ์ES6

ปัญหาของคุณ:ฉันเชื่อว่าคุณกำลังทำสิ่งที่ชอบ:

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

คาดว่าbarจะได้รับการกำหนดค่าของการส่งออกเริ่มต้น แต่อย่างที่เราเห็นในตัวอย่างข้างต้นการส่งออกเริ่มต้นจะถูกกำหนดให้กับdefaultทรัพย์สิน!

ดังนั้นเพื่อเข้าถึงการส่งออกเริ่มต้นเราต้องทำจริง

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

ถ้าเราใช้ไวยากรณ์โมดูล ES6 ได้แก่

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

บาเบลจะเปลี่ยนให้เป็น

'use strict';

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

var _input2 = _interopRequireDefault(_input);

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

console.log(_input2.default);

คุณจะเห็นว่าการเข้าถึงทุกแปลงเป็นเข้าถึงbar.default


เราไม่มีสิ่งที่เหมือนกันสำหรับสิ่งนี้ใช่ไหม
เบอร์กิ

3
@ Bergi: ฉันไม่ได้ค้นหา tbh (อัปยศฉัน :() มีคำถามแน่นอนเกี่ยวกับปัญหาเดียวกัน แต่ถามในวิธีที่แตกต่างกันแจ้งให้เราทราบหากคุณพบสิ่งที่เหมาะ!
Felix Kling

1
ตกลงใช้เวลาพอสมควรในการค้นหาสิ่งเหล่านี้ แต่ตอนนี้คุณสามารถใช้พลังที่ได้มาใหม่และเลือกหนึ่งในวิธีใช้ ES6“ ค่าเริ่มต้นการส่งออก” อย่างถูกต้องกับ CommonJS“ ต้องการ” และไม่สามารถต้องการ () ค่าการส่งออกเริ่มต้นใน Babel 6.xเป็นเป้าหมายแบบดูเพ :-)
Bergi

1
แดกดันที่ฉันสามารถทำได้ตอนนี้: D
เฟลิกซ์คลิง

1
@djKianoosh: ดูตัวเอง หลังจากมอบหมายให้module.exports, exportsและmodule.exportsมีค่าที่แตกต่างกันจึงมอบหมายให้exports.defaultsไม่มีผล (เพราะmodule.exportsเป็นสิ่งที่ได้รับการส่งออก) ในคำอื่น ๆ module.exports = { ... }ก็เหมือนกับถ้าคุณไม่เพียง
เฟลิกซ์คลิง

1

คุณต้องกำหนดค่า babel ให้ถูกต้องในโครงการของคุณเพื่อใช้การส่งออกเริ่มต้นและส่งออก const foo

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

จากนั้นเพิ่มการกำหนดค่าด้านล่างใน .abelrc

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

1

Felix Kling ทำการเปรียบเทียบที่ดีกับทั้งสองกรณีนี้สำหรับทุกคนที่สงสัยว่าจะเริ่มต้นการส่งออกควบคู่กับการส่งออกที่มีชื่อกับ module.exports ใน nodejs ได้อย่างไร

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

tl; dr ในตอนนี้เพื่อให้ใช้งานได้ไฟล์ที่ต้องการหรือนำเข้าSlimShadyจะต้องรวบรวมโดยใช้ Babel ด้วย'use strict'ต้องได้รับการรวบรวมโดยใช้บาเบลกับ

ฉันกำลังใช้ babel-cli 6.18.0 ในโครงการที่ฉันพบข้อผิดพลาดในตอนแรก

ไม่มี'use strict'ข่าวร้ายหมี

var 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

13
มันไม่สมเหตุสมผล ทุกแหล่งที่ใช้importการประกาศเป็นโมดูลและแหล่งข้อมูลนั้นเข้มงวดอยู่แล้ว ความแตกต่างที่เกิดขึ้นจริงนั้นเกี่ยวกับการต้องการการนำเข้า
Bergi

1
สิ่งที่จะทำให้ความรู้สึกที่จะใช้importแทนrequireและแทนexport default exports.default
Corey Alix


104
นี้จะต้องมีคำตอบ downvoted ที่สุดที่ฉันเคยเห็นใน StackOverflow
จิมมี่

4
@Jimi นั่นเป็นเพราะเป็นคำตอบที่ถูกโหวตมากที่สุดอันดับที่สี่ในเว็บไซต์ทั้งหมด
pppery
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.