Różnica między „require (x)” i „import x”

190

Właśnie zacząłem pracować nad małym projektem węzła, który będzie współpracował z MongoDB. Jednak wydaje mi się, że nie mogę poprawnie zaimportować odpowiednich modułów węzłów, mimo że zainstalowałem je poprawnie za pośrednictwem npm.

Na przykład poniższy kod zgłasza błąd informujący mnie, że „ekspres nie ma domyślnego eksportu”:

import express from "express";

Jednak ten kod działa:

const express = require("express");

Moje pytanie brzmi więc, jaka jest różnica w działaniu metod import i zmienna / wymagająca? Chciałbym naprawić wszystko, co nęka mój import w projekcie, ponieważ wydaje się, że może powodować dodatkowe problemy w przyszłości.

austinthemassive
źródło
O ile nie dołączysz definicji typowania dla express, pierwsza forma nie będzie miała sensu - w takim przypadku możesz użyć drugiej formy, ale zmienna expressbędzie typu any. Możesz dołączyć definicje stąd npmjs.com/package/@types/express
Filipe Sabella

Odpowiedzi:

225

Ten prosty diagram, który pomaga mi zrozumieć różnicę między requirei import.

wprowadź opis obrazu tutaj

Oprócz tego,

Nie możesz selektywnie ładować tylko tych elementów, których potrzebujesz, requireale importsmożesz selektywnie ładować tylko te elementy, których potrzebujesz. To może oszczędzić pamięć.

Ładowanie jest synchroniczne (krok po kroku), requirez drugiej strony importmoże być asynchroniczne (bez czekania na poprzedni import), więc może działać trochę lepiej niż require .

Zawsze słonecznie
źródło
Największą różnicą wpływającą na kod jest to, że eksporty w modułach CommonJS są „obliczane”, podczas gdy eksporty w module ESM są statyczne (wstępnie zdefiniowane). JS może określić eksporty w module ESM tylko po przeanalizowaniu kodu (jeszcze go nie uruchomił). W module commonJS eksporty są znane tylko wtedy, gdy moduł faktycznie działa i widzisz, do czego jest przypisane, module.exportsgdy kod inicjujący moduł zakończy działanie. Już sama ta różnica powoduje problemy ze zgodnością, gdy próbuje się sprawić, by pojedynczy moduł działał zarówno dla ESM, jak i CommonJS.
jfriend00
Moduły ESM są bardziej przyjazne dla bundlerów, ale są bardziej restrykcyjne dla programistów, ponieważ nie można obliczać eksportu w modułach ESM.
jfriend00
76

Główna różnica między requirei import, polega na tym, że requireautomatycznie skanuje w node_modulescelu znalezienia modułów, ale importwersja pochodząca z ES6 nie.

Większość ludzi używa babel do kompilacji importi export, co sprawia, że importdziała tak samo jak require.

Przyszła wersja Node.js może obsługiwać się importsama (w rzeczywistości wersja eksperymentalna już to robi ) i sądząc po uwagach Node.js, importnie będzie obsługiwać node_modules, opiera się na ES6 i musi określać ścieżkę modułu.

Więc sugerowałbym nie używać importz babel, ale ta funkcja nie jest jeszcze potwierdzona, może obsługiwać node_modulesw przyszłości, kto by wiedział?


Dla odniesienia, poniżej znajduje się przykład, jak babel może konwertować importskładnię ES6 na składnię CommonJS require.

Powiedzmy, że plik app_es6.jszawiera ten import:

import format from 'date-fns/format';

Jest to dyrektywa służąca do importowania funkcji formatu z pakietu węzła date-fns .

Powiązany package.jsonplik może zawierać coś takiego:

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

Powiązany .babelrcplik może wyglądać mniej więcej tak:

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

Ten build-server-fileskrypt zdefiniowany w package.jsonpliku jest dyrektywą dla babel do parsowania app_es6.jspliku i wyprowadzania pliku app.js.

Po uruchomieniu build-server-fileskryptu, jeśli otworzysz app.jsi poszukasz date-fnsimportu, zobaczysz, że został on przekształcony w ten sposób:

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

var _format2 = _interopRequireDefault(_format);

Większość tego pliku jest gobbledygook dla większości ludzi, jednak komputery to rozumieją.


Również w celach informacyjnych, jako przykład tego, jak moduł można utworzyć i zaimportować do projektu, jeśli zainstalujesz, date-fnsa następnie otworzysz node_modules/date-fns/get_year/index.js, możesz zobaczyć, że zawiera:

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

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

module.exports = getYear

Korzystając z powyższego procesu babel, twój app_es6.jsplik może zawierać:

import getYear from 'date-fns/get_year';

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

Babel konwertuje import na:

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

var _get_year2 = _interopRequireDefault(_get_year);

I odpowiednio obsłuż wszystkie odwołania do funkcji.

Ayon Lee
źródło
aaaaahhhhhh. Babel nie został zainstalowany w tym konkretnym projekcie, więc wszystko ma sens. Myślałem, że import / eksport ES6 już działał, ale teraz rozumiem, że Babel po prostu zmienia wszystko na requiretak czy inaczej
austinthemassive
na razie trzymać się wymagań. Zawsze możesz to zmienić w przyszłości bez żadnego problemu
Juan
1
import won't support node_modulesCo masz przez to na myśli?
PrivateOmega
11

Podam przykład dołączenia modułu ekspresowego z wymaganiem i importem

-wymagać

var express = require('express');

-import

import * as  express from 'express';

Tak więc po użyciu którejkolwiek z powyższych instrukcji będziemy mieć u nas zmienną o nazwie „express”. Teraz możemy zdefiniować zmienną „app” jako:

var app = express(); 

Dlatego używamy „require” z „CommonJS” i „import” z „ES6”.

Aby uzyskać więcej informacji o „wymaganiu” i „imporcie”, przeczytaj poniższe linki.

require - Wymaganie modułów w Node.js: wszystko, co musisz wiedzieć

import - aktualizacja modułów ES6 w Node.js.

saikiran_hegde
źródło
3

Brak odpowiedzi, a raczej komentarz, przepraszam, ale nie mogę komentować.

W węźle V10 możesz użyć flagi, --experimental-modulesaby powiedzieć Nodejs, którego chcesz użyć import. Ale twój skrypt wejściowy powinien kończyć się na .mjs.

Należy pamiętać, że jest to nadal rzecz eksperymentalna i nie należy jej używać w produkcji.

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

Ref 1 - Nodejs Doc

Ref 2 - problem z githubem

Tianpeng. Xia
źródło
3

nowy ES6:

`` import '' należy używać ze słowami kluczowymi `` eksport '', aby udostępniać zmienne / tablice / obiekty między plikami js:

export default myObject;

//....in another file

import myObject from './otherFile.js';

stara szkoła:

„require” powinno być używane z „module.exports”

 module.exports = myObject;

//....in another file

var myObject = require('./otherFile.js');
LaZza
źródło