ความแตกต่างระหว่าง“ require (x)” และ“ import x”


192

ฉันเพิ่งเริ่มทำงานกับโปรเจ็กต์โหนดขนาดเล็กที่จะเชื่อมต่อกับ MongoDB npmแต่ผมไม่สามารถดูเหมือนจะได้รับโมดูลโหนดที่เกี่ยวข้องที่จะนำเข้าอย่างถูกต้องถึงแม้ว่าผมได้ติดตั้งอย่างถูกต้องผ่าน

ตัวอย่างเช่นรหัสต่อไปนี้เกิดข้อผิดพลาดโดยบอกฉันว่า "express ไม่มีการส่งออกเริ่มต้น":

import express from "express";

อย่างไรก็ตามรหัสนี้ใช้งานได้:

const express = require("express");

ดังนั้นคำถามของฉันคืออะไรความแตกต่างในวิธีการนำเข้าและตัวแปร / ต้องการวิธีการทำงานอย่างไร ฉันต้องการแก้ไขสิ่งที่ทำให้เกิดการนำเข้าของฉันในโครงการเนื่องจากดูเหมือนว่าจะทำให้เกิดปัญหาเพิ่มเติมตามถนน


ถ้าคุณรวมถึงคำจำกัดความของการพิมพ์สำหรับด่วนรูปแบบครั้งแรกจะไม่ทำให้รู้สึก - ในกรณีนี้คุณสามารถใช้แบบฟอร์มที่สอง แต่ตัวแปรจะเป็นประเภทexpress anyคุณสามารถรวมคำจำกัดความได้จากที่นี่npmjs.com/package/@types/express
Filipe Sabella

2
การทำสำเนาซ้ำที่เป็นไปได้ของการใช้ Node.js ต้องการกับการนำเข้า / ส่งออก ES6
Ryall

คำตอบ:


231

แผนภาพนี้ง่ายที่จะช่วยให้ผมที่จะเข้าใจความแตกต่างระหว่างและrequireimport

ป้อนคำอธิบายรูปภาพที่นี่

นอกเหนือจากนี้,

คุณไม่สามารถเลือกโหลดเฉพาะชิ้นส่วนที่คุณต้องการได้requireแต่ด้วยimportsคุณสามารถเลือกโหลดเฉพาะชิ้นส่วนที่คุณต้องการ ที่สามารถบันทึกความจำ

การโหลดแบบซิงโครนัส (ทีละขั้นตอน) สำหรับrequireในอีกทางimportสามารถแบบอะซิงโครนัส (โดยไม่ต้องรอการนำเข้าก่อนหน้า) เพื่อให้สามารถทำงานได้ดีกว่า requireเล็กน้อย


ความแตกต่างที่ยิ่งใหญ่ที่สุดที่มีผลต่อโค้ดคือการเอ็กซ์พอร์ตในโมดูล CommonJS นั้น "คำนวณ" ในขณะที่การส่งออกในโมดูล ESM เป็นแบบสแตติก (กำหนดไว้ล่วงหน้า) JS สามารถกำหนดการส่งออกในโมดูล ESM หลังจากแยกวิเคราะห์รหัสเท่านั้น (ยังไม่ได้เรียกใช้) ในโมดูล commonJS การส่งออกจะทราบได้เฉพาะเมื่อโมดูลทำงานจริงและคุณจะเห็นสิ่งที่กำหนดให้module.exportsเมื่อรหัสการเริ่มต้นโมดูลเสร็จสิ้นการทำงาน ความแตกต่างนี้สร้างความปวดหัวที่เข้ากันได้เพียงอย่างเดียวในการพยายามทำให้โมดูลเดียวทำงานได้ทั้ง ESM และ CommonJS
jfriend00

โมดูล ESM นั้นเป็นมิตรต่อผู้ใช้ แต่เป็นข้อ จำกัด ของ coders เนื่องจากคุณไม่สามารถคำนวณการเอ็กซ์พอร์ตในโมดูล ESM ได้
jfriend00

77

ความแตกต่างที่สำคัญระหว่างrequireและimportคือrequireจะสแกนnode_modulesหาโมดูลโดยอัตโนมัติimportมาจาก ES6 จะไม่

คนส่วนใหญ่ใช้บาเบลเพื่อรวบรวมimportและexportทำให้การimportกระทำเหมือนกันrequireทำหน้าที่เช่นเดียวกับ

เวอร์ชันในอนาคตของ Node.js อาจสนับสนุนimportตัวเอง (จริง ๆแล้วเวอร์ชันทดลองทำไปแล้ว ) และการตัดสินโดยบันทึกของ Node.js importจะไม่สนับสนุนnode_modulesมันขึ้นอยู่กับ ES6 และต้องระบุเส้นทางของโมดูล

ดังนั้นฉันขอแนะนำให้คุณไม่ใช้importกับ Babel แต่คุณสมบัตินี้ยังไม่ได้รับการยืนยันมันอาจรองรับnode_modulesในอนาคตใครจะรู้


สำหรับการอ้างอิงด้านล่างเป็นตัวอย่างของวิธีที่ babel สามารถแปลงimportไวยากรณ์ของ ES6 เป็นCommonJS ได้requireไวยากรณ์

สมมติว่าไฟล์app_es6.jsมีการนำเข้านี้:

import format from 'date-fns/format';

นี่คือคำสั่งที่จะนำเข้ารูปแบบฟังก์ชั่นจากแพคเกจโหนดวัน FNS

package.jsonไฟล์ที่เกี่ยวข้องอาจมีลักษณะดังนี้:

"scripts": {
    "start": "node app.js",
    "build-server-file": "babel app_es6.js --out-file app.js",
    "webpack": "webpack"
}

.babelrcไฟล์ที่เกี่ยวข้องอาจเป็นดังนี้:

{
    "presets": [
        [
            "env",
            {
                "targets":
                {
                    "node": "current"
                }
            }
        ]
    ]
}

นี้build-server-fileสคริปต์ที่กำหนดไว้ในpackage.jsonไฟล์สั่งสำหรับบาเบลที่จะแยกเป็นไฟล์และการส่งออกไฟล์ app_es6.jsapp.js

หลังจากเรียกใช้build-server-fileสคริปต์ถ้าคุณเปิดapp.jsและค้นหาdate-fnsการนำเข้าคุณจะเห็นว่ามีการแปลงเป็น:

var _format = require("date-fns/format");

var _format2 = _interopRequireDefault(_format);

ไฟล์ส่วนใหญ่เป็น gobbledygook สำหรับมนุษย์ส่วนใหญ่ แต่คอมพิวเตอร์เข้าใจ


นอกจากนี้สำหรับการอ้างอิงเป็นตัวอย่างของวิธีการสร้างและนำเข้าโมดูลในโครงการของคุณถ้าคุณติดตั้งdate-fnsแล้วเปิดnode_modules/date-fns/get_year/index.jsคุณจะเห็นว่ามันมี:

var parse = require('../parse/index.js')

function getYear (dirtyDate) {
  var date = parse(dirtyDate)
  var year = date.getFullYear()
  return year
}

module.exports = getYear

เมื่อใช้กระบวนการบาเบลด้านบนapp_es6.jsไฟล์ของคุณอาจมี:

import getYear from 'date-fns/get_year';

// Which year is 2 July 2014?
var result = getYear(new Date(2014, 6, 2))
//=> 2014

และ Babel จะแปลงการนำเข้าเป็น:

var _get_year = require("date-fns/get_year");

var _get_year2 = _interopRequireDefault(_get_year);

และจัดการการอ้างอิงทั้งหมดไปยังฟังก์ชั่นตามลำดับ


aaaaahhhhhh บาเบลไม่ได้รับการติดตั้งในโครงการนี้ซึ่งทำให้ทุกอย่างเข้าท่า ฉันคิดว่าการนำเข้า / ส่งออก ES6 ทำงานได้แล้ว แต่ตอนนี้ฉันเข้าใจแล้วว่าบาเบลกำลังเปลี่ยนทุกอย่างเป็นrequireใหม่
austinthemassive

ติดต้องสำหรับตอนนี้ คุณสามารถเปลี่ยนได้ในอนาคตโดยไม่มีปัญหา
Juan

1
import won't support node_modulesคุณหมายถึงอะไร
PrivateOmega

11

ให้ฉันยกตัวอย่างสำหรับการรวมโมดูลด่วนด้วยความต้องการ & นำเข้า

-จำเป็นต้อง

var express = require('express');

นำเข้า

import * as  express from 'express';

ดังนั้นหลังจากใช้คำสั่งข้างต้นเราจะมีตัวแปรที่เรียกว่า 'ด่วน' กับเรา ตอนนี้เราสามารถกำหนดตัวแปร 'แอป' เป็น

var app = express(); 

ดังนั้นเราจึงใช้ 'ต้องการ' กับ 'CommonJS' และ 'นำเข้า' กับ 'ES6'

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ 'ต้องการ' & 'นำเข้า' โปรดอ่านลิงก์ด้านล่าง

need - ต้องการโมดูลใน Node.js: ทุกสิ่งที่คุณจำเป็นต้องรู้

นำเข้า - อัปเดตเกี่ยวกับโมดูล ES6 ใน Node.js


3

ไม่ใช่คำตอบที่นี่และอื่น ๆ เช่นความคิดเห็นขอโทษ แต่ฉันไม่สามารถแสดงความคิดเห็น

ในโหนด V10 คุณสามารถใช้ธง--experimental-modulesที่จะบอก Nodejs importคุณต้องการที่จะใช้ แต่สคริปต์รายการของคุณควรลงท้ายด้วย.mjsแต่สคริปต์รายการของคุณควรจะจบลงด้วยการ

โปรดทราบว่านี่ยังเป็นสิ่งทดลองและไม่ควรใช้ในการผลิต

// main.mjs
import utils from './utils.js'
utils.print();
// utils.js
module.exports={
    print:function(){console.log('print called')}
}

Ref 1 - Nodejs Doc

การอ้างอิง 2 - ปัญหา GitHub


3

ใหม่ ES6:

ควรใช้ 'นำเข้า' กับคำสำคัญ 'ส่งออก' เพื่อแบ่งปันตัวแปร / อาร์เรย์ / วัตถุระหว่างไฟล์ js:

export default myObject;

//....in another file

import myObject from './otherFile.js';

Skool เก่า:

ควรใช้ 'ต้องการ' กับ 'module.exports'

 module.exports = myObject;

//....in another file

var myObject = require('./otherFile.js');
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.