A diferença entre "exigir (x)" e "importar x"

190

Acabei de começar a trabalhar em um projeto de pequeno nó que fará interface com um MongoDB. No entanto, não consigo obter os módulos de nó relevantes para importar corretamente, mesmo que eu os tenha instalado corretamente via npm.

Por exemplo, o código a seguir gera um erro, informando que "o express não tem exportação padrão":

import express from "express";

No entanto, este código funciona:

const express = require("express");

Então, minha pergunta é: qual é a diferença de como os métodos import e variável / exigem funcionam? Gostaria de corrigir o que está afetando minhas importações no projeto, pois parece provável que cause problemas adicionais no futuro.

austinthemassive
fonte
A menos que você inclua as definições de digitação para express, o primeiro formulário não fará sentido - nesse caso, você poderá usar o segundo formulário, mas a variável expressserá do tipo any. Você pode incluir as definições aqui npmjs.com/package/@types/express
Filipe Sabella

Respostas:

227

Este diagrama simples que me ajuda a entender a diferença entre requiree import.

insira a descrição da imagem aqui

Além disso,

Você não pode carregar seletivamente apenas as peças de que precisa, requiremas importspode carregar seletivamente apenas as peças de que precisa. Isso pode economizar memória.

O carregamento é síncrono (passo a passo), pois, requirepor outro lado, importpode ser assíncrono (sem aguardar a importação anterior), por isso pode ter um desempenho um pouco melhor que require .

Sempre ensolarado
fonte
A maior diferença que afeta o código é que as exportações nos módulos CommonJS são "computadas", enquanto as exportações em um módulo ESM são estáticas (predefinidas). JS pode determinar as exportações em um módulo ESM depois de analisar apenas o código (ainda não o está executando). Em um módulo commonJS, as exportações são conhecidas apenas quando o módulo realmente é executado e você vê o que é designado module.exportsquando o código de inicialização do módulo termina a execução. Somente essa diferença cria dores de cabeça de compatibilidade na tentativa de fazer um único módulo funcionar para o ESM e o CommonJS.
jfriend00 5/06
Os módulos ESM são mais amigáveis ​​aos empacotadores, mas são mais restritivos aos codificadores porque você não pode ter exportações calculadas nos módulos ESM.
jfriend00 5/06
76

A principal diferença entre requiree import, é que requireela varrerá automaticamente node_modulespara encontrar módulos, mas import, que vem do ES6, não será.

A maioria das pessoas usa o babel para compilar importe export, o que faz importagir da mesma maneira que require.

A versão futura do Node.js pode suportar a importsi própria (na verdade, a versão experimental já suporta ) e, a julgar pelas notas do Node.js., importnão suporta node_modules, baseia-se no ES6 e deve especificar o caminho do módulo.

Então, eu sugiro que você não use importcom babel, mas esse recurso ainda não está confirmado, ele pode suportar node_modulesno futuro, quem saberia?


Para referência, abaixo está um exemplo de como o babel pode converter a importsintaxe do ES6 na sintaxe do CommonJS require.

Digamos que o arquivo app_es6.jscontenha esta importação:

import format from 'date-fns/format';

Esta é uma diretiva para importar a função format do pacote de nós date-fns .

O package.jsonarquivo relacionado pode conter algo como isto:

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

O .babelrcarquivo relacionado pode ser algo como isto:

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

Este build-server-filescript definido no package.jsonarquivo é uma diretiva para o babel analisar o app_es6.jsarquivo e produzi-lo app.js.

Após executar o build-server-filescript, se você abrir app.jse procurar a date-fnsimportação, verá que ela foi convertida para isso:

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

var _format2 = _interopRequireDefault(_format);

A maior parte desse arquivo é um aviso para a maioria dos humanos, no entanto os computadores o entendem.


Também para referência, como um exemplo de como um módulo pode ser criado e importado para o seu projeto, se você instalar date-fnse abrir, node_modules/date-fns/get_year/index.jspoderá ver que ele contém:

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

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

module.exports = getYear

Usando o processo babel acima, seu app_es6.jsarquivo pode conter:

import getYear from 'date-fns/get_year';

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

E babel converteria as importações em:

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

var _get_year2 = _interopRequireDefault(_get_year);

E lide com todas as referências à função de acordo.

Ayon Lee
fonte
aaaaahhhhhh. Babel não foi instalado neste projeto em particular, o que faz tudo fazer sentido. Eu pensei que as importações ES6 / exportações já estavam funcional, mas agora eu entendo que Babel é apenas mudar tudo para requirequalquer maneira
austinthemassive
stick para exigir por enquanto. Você sempre pode mudá-lo no futuro, sem qualquer problema
Juan
1
import won't support node_modulesO que você quer dizer com isso?
PrivateOmega
11

Deixe-me dar um exemplo para incluir o módulo expresso com exigir e importar

-requir

var express = require('express');

-importar

import * as  express from 'express';

Então, depois de usar qualquer uma das afirmações acima, teremos uma variável chamada como 'expressa' conosco. Agora podemos definir a variável 'app' como,

var app = express(); 

Portanto, usamos 'require' com 'CommonJS' e 'import' com 'ES6'.

Para mais informações sobre 'exigir' e 'importar', leia os links abaixo.

require - Exigindo módulos no Node.js: tudo o que você precisa saber

import - Uma atualização nos módulos ES6 no Node.js

saikiran_hegde
fonte
3

Não é uma resposta aqui e mais como um comentário, desculpe, mas não posso comentar.

No nó V10, você pode usar o sinalizador --experimental-modulespara informar ao Nodejs que deseja usar import. Mas seu script de entrada deve terminar com .mjs.

Observe que isso ainda é experimental e não deve ser usado na produção.

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

Ref 1 - Doc do Nodejs

Ref 2 - questão do github

Tianpeng. Xia
fonte
3

novo ES6:

'import' deve ser usado com as palavras-chave 'export' para compartilhar variáveis ​​/ matrizes / objetos entre arquivos js:

export default myObject;

//....in another file

import myObject from './otherFile.js';

skool antigo:

'require' deve ser usado com 'module.exports'

 module.exports = myObject;

//....in another file

var myObject = require('./otherFile.js');
LaZza
fonte