Разница между «требовать (х)» и «импортировать х»


194

Я только начал работать над небольшим проектом, который будет взаимодействовать с MongoDB. Тем не менее, я не могу заставить соответствующие модули узла правильно импортировать, даже если я правильно их установил npm.

Например, следующий код выдает ошибку, сообщая, что «экспресс не имеет экспорта по умолчанию»:

import express from "express";

Тем не менее, этот код работает:

const express = require("express");

Итак, мой вопрос: в чем разница в том, как функционируют методы import и variable / require? Я хотел бы исправить все, что мешает моему импорту в проекте, так как это может вызвать дополнительные проблемы в будущем.


Если вы не включите определения для экспресс-выражения, первая форма не будет иметь смысла - в этом случае вы можете использовать вторую форму, но переменная expressбудет иметь тип any. Вы можете включить определения отсюда npmjs.com/package/@types/express
Филипе Сабелла

Ответы:


235

Эта простая диаграмма, которая помогает мне понять разницу между requireи import.

введите описание изображения здесь

Помимо этого,

Вы не можете выборочно загружать только те части, которые вам нужны, requireно importsвы можете выборочно загружать только те части, которые вам нужны. Это может сохранить память.

Загрузка является синхронной (шаг за шагом), поскольку, requireс другой стороны, importможет быть асинхронной (без ожидания предыдущего импорта), поэтому она может работать немного лучше, чем require .


Самое большое различие, которое влияет на код, состоит в том, что экспорт в модулях CommonJS «вычисляется», тогда как экспорт в модуле ESM является статическим (предопределенным). JS может определить экспорт в модуле ESM только после анализа кода (еще не выполняя его). В модуле commonJS экспорт известен только тогда, когда модуль действительно работает, и вы видите, что назначено, module.exportsкогда код инициализации модуля завершает работу. Одно это различие создает проблемы совместимости при попытке заставить работать один модуль как для ESM, так и для CommonJS.
jfriend00

Модули ESM более дружественны к упаковщикам, но более ограничены для кодеров, потому что вы не можете рассчитывать экспорт в модулях ESM.
jfriend00

77

Основное различие между requireи importзаключается в том, что он requireбудет автоматически сканировать node_modulesдля поиска модулей, но import, исходя из ES6, не будет.

Большинство людей используют Babel для компиляции 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';

Это директива для импорта функции форматирования из пакета узла 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

Используя описанный выше процесс babel, ваш 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. Babel не был установлен на этот конкретный проект, который имеет смысл. Я думал, что импорт / экспорт ES6 уже функционирует, но теперь я понимаю, что Babel просто все меняет на все requireравно
austinthemassive

придерживаться требовать сейчас. Вы всегда можете изменить его в будущем без каких-либо проблем
Хуан,

2
import won't support node_modulesЧто ты имел в виду под этим?
PrivateOmega

11

Позвольте мне привести пример для включения экспресс-модуля с require & import

-require

var express = require('express');

-Импортировать

import * as  express from 'express';

Таким образом, после использования любого из приведенных выше утверждений у нас будет переменная с именем «express». Теперь мы можем определить переменную app как:

var app = express(); 

Поэтому мы используем 'require' с 'CommonJS' и 'import' с 'ES6'.

Чтобы узнать больше о 'require' & 'import', прочитайте ссылки ниже.

require - Требование модулей в Node.js: все, что вам нужно знать

import - Обновление модулей 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')}
}

Ссылка 1 - Документ Nodejs

Ссылка 2 - выпуск github


3

новый 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');
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.