node.js - ההבדל בין "require(x)" ל"import x"
רק התחלתי לעבוד על פרויקט Node קטן שיתחבר ל-MongoDB. עם זאת, אני לא מצליח לייבא את המודולים הרלוונטיים של Node כמו שצריך, למרות שהתקנתי אותם כראוי דרך npm.
לדוגמה, הקוד הבא זורק שגיאה, ואומר לי ש"ל-express אין ייצוא ברירת מחדל":
import express from "express";
עם זאת, הקוד הזה עובד:
const express = require("express");
אז השאלה שלי היא, מה ההבדל בדרך שבה פונקציות import ופונקציות המשתנה/require עובדות? אני רוצה לתקן את מה שמפריע לי ב-imports בפרויקט, כי זה נראה סביר שעלול לגרום לבעיות נוספות בעתיד.
תשובה #1
התמונה הפשוטה הזו תעזור לך להבין את ההבדלים בין require ל-import.
חוץ מזה,
אתה לא יכול לטעון באופן סלקטיבי רק את החלקים שאתה צריך עם require, אבל עם import, אתה יכול לטעון באופן סלקטיבי רק את החלקים שאתה צריך, מה שיכול לחסוך בזיכרון.
הטענה היא סינכרונית (צעד אחרי צעד) עבור require מצד שני import יכול להיות אסינכרוני (בלי להמתין לייבוא קודם) כך שהוא יכול לבצע קצת טוב יותר מאשר require.
תשובה #2
ההבדל העיקרי בין require ל-import, הוא ש-import מובנה ב-JS, אבל require זמין רק ב-Node.js.
לצורך התייחסות, למטה מופיע דוגמה לאופן שבו Babel יכול להמיר את הסינטקס import של ES6 לסינטקס require של CommonJS. שימו לב שמאז Node.js גרסה 12, אין צורך לעשות זאת.
נניח כי הקובץ app_es6.js מכיל את הייבוא הבא:
import format from 'date-fns/format';
זוהי הוראה לייבא את הפונקציה format מהחבילה node בשם date-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 הוא הוראה ל-babel לנתח את הקובץ app_es6.js ולהפיק את הקובץ app.js.
לאחר הרצת הסקריפט build-server-file, אם תפתח את app.js ותחפש את היבוא של date-fns, תראה שהוא הומר ל:
var _format = require("date-fns/format");
var _format2 = _interopRequireDefault(_format);
רוב הקובץ הזה הוא ג'יבריש עבור רוב האנשים, אך מחשבים מבינים אותו.
גם כהפניה, כדוגמה לאיך אפשר ליצור מודול ולייבא אותו לפרויקט שלך, אם תתקין את 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
ובבל יהפוך את הייבוא ל:
var _get_year = require("date-fns/get_year");
var _get_year2 = _interopRequireDefault(_get_year);
ולטפל בכל ההתייחסויות לפונקציה בהתאם.
תשובה #3
תן לי לתת דוגמה לכלילת מודול express עם require ו-import
-require
var express = require('express');
-import
import * as express from 'express';
אז אחרי שימוש באחת מההצהרות שלמעלה, יהיה לנו משתנה שנקרא 'express'. עכשיו נוכל להגדיר את המשתנה 'app' כ
var app = express();
אז אנחנו משתמשים ב-'require' עם 'CommonJS' וב-'import' עם 'ES6'.
למידע נוסף על 'require' ו-'import', עיינו בקישורים למטה.
require - דרישת מודולים ב-Node.js: כל מה שאתה צריך לדעת
ייבוא - עדכון על מודולי ES6 ב-Node.js
תשובה #4
אני אעשה את זה פשוט,
- ייבוא וייצוא הם תכונות של ES6 (JavaScript בדור הבא).
- Require הוא שיטה ישנה לייבוא קוד מקבצים אחרים
ההבדל העיקרי הוא ב-require, הקובץ JS כולו נקרא או כלול. אפילו אם אינך צריך חלק ממנו.
var myObject = require('./otherFile.js'); //This JS file will be included fully.
בעוד שבייבוא ניתן לחלץ רק אובייקטים/פונקציות/משתנים הנדרשים.
import { getDate }from './utils.js';
//Here I am only pulling getDate method from the file instead of importing full file
הבדל משמעותי נוסף הוא שאתה יכול להשתמש ב-require בכל מקום בתוכנית, בעוד ש-import צריך תמיד להיות בראש הקובץ
עריכה: בגרסאות האחרונות של Node ניתן להשתמש בפירוק מבנה. זה ייראה כך
const { getDate } = require('./date.js');
תשובה #5
ES6 חדש:
'import' צריך להיות בשימוש עם מילות המפתח 'export' כדי לשתף משתנים/מערכים/אובייקטים בין קבצי js:
export default myObject;
//....in another file
import myObject from './otherFile.js';
ישן בית ספר:
יש להשתמש ב-'require' עם 'module.exports'
module.exports = myObject;
//....in another file
var myObject = require('./otherFile.js');
תשובה #6
יש הבדל גדול בין זה:
import express from "express";
ועכשיו זה:
import * as express from "express";
התרגום הנכון מ-CommonJS ל-ES6 של
const express = require("express");
היא הייבוא השני.
בעצם, זה בגלל שבייבוא הראשון אתה מחפש ייצוא במודול express בשם express. בשני אתה מייבא את כל מודול express בשם express.
תשובה #7
import (תחביר מודולים של ES) | require (תחביר של מודולים CommonJS) | |
|---|---|---|
| סיכום | זו התקן העדכני ביותר לעבודה עם מודולים ב-JavaScript ומודרכת בדפדפנים מודרניים ובסביבות שמתרגמות או תומכות ב-ES6, כמו TypeScript או Babel. | זה לא היה במקור חלק מ-JavaScript, אבל זה אומץ כסטנדרט עבור Node.js, ששימש באופן שוטף בפיתוח בצד השרת ב-JavaScript. |
| ייצוא | סטטי (מוגדר מראש). מבנה הייצוא של המודול נקבע כאשר הקוד מנותח, לא בזמן הריצה. הטבע הסטטי הזה מאפשר לכלים כמו באנדלרים ולינטרים לנתח את הקוד מבלי להפעילו, ובכך מאפשר תכונות כמו Tree-shaking טוב יותר וזמני טעינה מהירים יותר בדפדפנים. | נחושב בזמן ריצה. הייצוא במודול נקבע במהלך ביצוע הקוד. |
| טוען מודולים | יכול להיות אסינכרוני, מה שמאפשר טעינה יעילה ובחירה של חלקי המודול. זה יכול להוביל לזמני טעינה מהירים יותר וביצועים טובים יותר. | סינכרוני (טוען מודולים אחד אחד). תמיד טוען את כל המודול, מה שיכול להשפיע על הביצועים אם המודול גדול. |
| דוגמה מלאה | | |
| היקף | | הייצוא מועתק בזמן דרישת המודול. |
אם קשה לקרוא כאן, קרא עותק של הטבלה הזו בגיטהאב.
