ti-enxame.com

Usando o Node.js requer vs. importação / exportação do ES6

Em um projeto em que estou colaborando, temos duas opções em qual sistema de módulo podemos usar:

  1. Importando módulos usando require e exportando usando module.exports e exports.foo.
  2. Importando módulos usando ES6 import e exportando usando ES6 export

Há algum benefício de desempenho em usar um sobre o outro? Existe algo mais que devemos saber se usarmos módulos do ES6 sobre os do Node?

752
kpimov

Há algum benefício de desempenho em usar um sobre o outro?

Lembre-se de que ainda não existe nenhum mecanismo JavaScript que ofereça suporte nativamente aos módulos ES6. Você mesmo disse que está usando Babel. O Babel converte a declaração import e export para CommonJS (require/module.exports) por padrão. Então, mesmo se você usar a sintaxe do módulo ES6, você estará usando o CommonJS sob o capô se você executar o código no Node.

Existem diferenças técnicas entre os módulos CommonJS e ES6, por ex. O CommonJS permite que você carregue módulos dinamicamente. O ES6 não permite isso, mas existe uma API em desenvolvimento para isso .

Como os módulos do ES6 fazem parte do padrão, eu os utilizaria.

617
Felix Kling

Existem vários usos/capacidades que você pode querer considerar:

Exigir:

  • Você pode ter carregamento dinâmico em que o nome do módulo carregado não é predefinido/estático ou em que você carrega condicionalmente um módulo apenas se for "realmente necessário" (dependendo de determinado fluxo de código).
  • O carregamento é síncrono. Isso significa que, se você tiver vários requires, eles serão carregados e processados ​​um por um.

Importações ES6:

  • Você pode usar importações nomeadas para carregar seletivamente apenas as partes necessárias. Isso pode economizar memória.
  • A importação pode ser assíncrona (e na atual ES6 Module Loader, na verdade é) e pode funcionar um pouco melhor.

Além disso, o sistema do módulo Require não é baseado em padrão. É altamente improvável que se torne padrão agora que os módulos ES6 existem. No futuro, haverá suporte nativo para módulos ES6 em várias implementações que serão vantajosas em termos de desempenho.

148
Amit

As principais vantagens são sintáticas:

  • Sintaxe mais declarativa/compacta
  • Os módulos ES6 farão basicamente o UMD (Universal Module Definition) obsoleto - essencialmente remove o cisma entre CommonJS e AMD (server vs browser).

É improvável que você veja benefícios de desempenho com os módulos ES6. Você ainda precisará de uma biblioteca extra para empacotar os módulos, mesmo quando houver suporte completo para recursos do ES6 no navegador.

36
snozza

Há algum benefício de desempenho em usar um sobre o outro?

A resposta atual é não, porque nenhum dos mecanismos de navegador atuais implementa import/export do padrão ES6.

Alguns gráficos de comparação http://kangax.github.io/compat-table/es6/ não levam isso em conta, então quando você vir quase todos os greens para o Chrome, tenha cuidado. A palavra-chave import do ES6 não foi levada em consideração.

Em outras palavras, os mecanismos de navegação atuais, incluindo o V8, não podem importar novo arquivo JavaScript do arquivo JavaScript principal através de qualquer diretiva JavaScript.

(Ainda podemos estar apenas alguns bugs de distância ou anos de distância até que o V8 implemente isso de acordo com a especificação do ES6.)

Este documento é o que precisamos, e isto documento é o que devemos obedecer.

E o padrão ES6 dizia que as dependências do módulo deveriam estar lá antes de lermos o módulo, como na linguagem de programação C, onde tínhamos (cabeçalhos) .h arquivos.

Essa é uma estrutura boa e bem testada, e tenho certeza de que os especialistas que criaram o padrão ES6 tinham isso em mente.

Isso é o que habilita o Webpack ou outros pacotes de pacotes a otimizar o pacote em alguns casos especiais e a reduzir algumas dependências do pacote que não são necessárias. Mas nos casos em que temos dependências perfeitas, isso nunca acontecerá.

Ele precisará de algum tempo até que o suporte nativo import/export seja ativado, e a palavra-chave require não irá a lugar nenhum por muito tempo.

O que é require?

Este é o modo node.js para carregar módulos. ( https://github.com/nodejs/node )

O nó usa métodos no nível do sistema para ler arquivos. Basicamente, você depende disso quando usar require. require terminará em alguma chamada de sistema como uv_fs_open (depende do sistema final, Linux, Mac, Windows) para carregar o arquivo/módulo JavaScript.

Para verificar se isso é verdade, tente usar Babel.js e você verá que a palavra-chave import será convertida em require.

enter image description here

30
prosti

Usando módulos ES6 pode ser útil para 'árvore tremendo'; isto é, habilitar o Webpack 2, Rollup (ou outros bundlers) para identificar caminhos de código que não são usados ​​/ importados e, portanto, não fazem parte do pacote resultante. Isso pode reduzir significativamente o tamanho do arquivo, eliminando o código que você nunca precisará, mas com o CommonJS é empacotado por padrão, porque o Webpack et al não tem como saber se é necessário.

Isso é feito usando a análise estática do caminho do código.

Por exemplo, usando:

import { somePart } 'of/a/package';

... dá ao bundler uma dica de que package.anotherPart não é necessário (se não for importado, não pode ser usado - certo?), então não vai incomodar o empacotamento.

Para habilitar isso para o Webpack 2, você precisa garantir que o seu transpilador não esteja cuspindo módulos do CommonJS. Se você estiver usando o es2015 plug-in com o babel, você pode desativá-lo em seu .babelrc da seguinte forma:

{
  "presets": [
    ["es2015", { modules: false }],
  ]
}

Rollup e outros podem funcionar de forma diferente - veja os documentos se estiver interessado.

28
Lee Benson

Quando se trata de assíncrono ou carregamento lento, então import () é muito mais poderoso. Veja quando exigimos o componente de maneira assíncrona, então usamos import de alguma maneira assíncrona como na variável const usando await.

const module = await import('./module.js');

Ou se você quiser usar require() então,

const converter = require('./converter');

A coisa é import() é na verdade assíncrona na natureza. Como mencionado por neehar venugopal em ReactConf , você pode usá-lo para carregar dinamicamente os componentes reagentes para a arquitetura do lado do cliente.

Também é muito melhor quando se trata de roteamento. Essa é a única coisa especial que faz com que o log de rede baixe uma parte necessária quando o usuário se conecta a um site específico para seu componente específico. por exemplo. Página de login antes que o painel não baixasse todos os componentes do painel. Porque o que é necessário atual, ou seja, componente de login, que só será baixado.

O mesmo vale para export: ES6 export é exatamente o mesmo que para CommonJS module.exports.

NOTE - Se você está desenvolvendo um projeto node.js, então você deve usar estritamente require() como nó irá lançar erro de exceção como invalid token 'import' se você usar import. Portanto, o nó não suporta instruções de importação

ATUALIZAÇÃO - Como sugerido por Dan Dascalesc : Desde a v8.5.0 (lançado em setembro de 2017), node --experimental-modules index.mjs permite que você use import sem Babel. Você pode (e deve) também publicar seus pacotes npm como ESModule nativo, com compatibilidade com versões anteriores para a antiga maneira require

Veja isto para mais depuração onde usar importações assíncronas - https://www.youtube.com/watch?v=bb6RCrDaxhw

14
Meet Zaveri

Eu pessoalmente uso importação porque, nós podemos importar os métodos requeridos, membros usando importação.

import {foo, bar} from "dep";

FileName: dep.js

export foo function(){};
export const bar = 22

O crédito vai para Paul Shan. Mais informações .

5
chandoo

A coisa mais importante a saber é que os módulos ES6 são, de fato, um padrão oficial, enquanto os módulos CommonJS (Node.js) não são.

Em 2019, os módulos do ES6 são suportados por 84% dos navegadores. Enquanto o Node.js os coloca atrás de um sinalizador - experimental-modules , há também um conveniente pacote node chamado esm , que torna a integração suave.

Outro problema que você provavelmente encontrará entre esses sistemas de módulos é a localização do código. O Node.js assume que a origem é mantida em um diretório node_modules, enquanto a maioria dos módulos do ES6 é implementada em uma estrutura de diretórios simples. Isso não é fácil de reconciliar, mas isso pode ser feito com o uso do seu arquivo package.json com scripts de pré e pós-instalação. Aqui está um exemplo módulo isomórfico e um artigo explicando como funciona.

4
isysd