Em um projeto em que estou colaborando, temos duas opções em qual sistema de módulos podemos usar:
- Importando módulos usando
require
e exportando usandomodule.exports
eexports.foo
. - Importando Módulos Usando ES6
import
e Exportando Usando ES6export
Existem benefícios de desempenho em usar um sobre o outro? Há mais alguma coisa que devemos saber se devemos usar os módulos ES6 em relação aos do nó?
javascript
node.js
ecmascript-6
babeljs
kpimov
fonte
fonte
node --experimental-modules index.mjs
permite usarimport
sem Babel e funciona no Nó 8.5.0+. Você pode (e deve) também publicar seus pacotes npm como ESModule nativo , com compatibilidade com versões anteriores darequire
maneira antiga .Respostas:
Lembre-se de que ainda não existe um mecanismo JavaScript que suporte nativamente os módulos ES6. Você mesmo disse que está usando Babel. Babel converte
import
eexport
declaração para CommonJS (require
/module.exports
) por padrão de qualquer maneira. Portanto, mesmo se você usar a sintaxe do módulo ES6, estará usando o CommonJS oculto se executar o código no Nó.Existem diferenças técnicas entre os módulos CommonJS e ES6, por exemplo, o CommonJS permite carregar módulos dinamicamente. O ES6 não permite isso, mas há uma API em desenvolvimento para isso .
Como os módulos ES6 fazem parte do padrão, eu os usaria.
fonte
ES6 import
comrequire
mas eles trabalharam de forma diferente. O CommonJS exporta a própria classe enquanto houver apenas uma classe. As exportações do ES6, como existem várias classes, devem ser usadas.ClassName
para obter a classe exportada. Existem outras diferenças que realmente afeta a implementaçãomodule.exports = ...;
é equivalente aexport default ...
.exports.foo = ...
é equivalente aexport var foo = ...
;import
para o CommonJS no Node, usado juntamente com o Webpack 2 / Rollup (e qualquer outro empacotador que permita agitar a árvore ES6), é possível terminar com um arquivo significativamente menor que as trocas de código equivalentes do Node através do usorequire
exatamente porque ES6 permite a análise estática de importação / exportação. Embora isso não faça diferença para o Node (ainda), certamente pode ocorrer se o código acabar como um único pacote de navegador.Existem vários usos / recursos que você pode querer considerar:
Exigir:
require
s, eles serão carregados e processados um a um.ES6 Importações:
Além disso, o sistema de módulos Exigir não é baseado em padrão. É altamente improvável que se torne padrão agora que existem módulos ES6. No futuro, haverá suporte nativo para os Módulos ES6 em várias implementações, o que será vantajoso em termos de desempenho.
fonte
require
qualquer maneira, portanto, estará usando o sistema de módulos e o carregador do Node de qualquer maneira.As principais vantagens são sintáticas:
É improvável que você veja quaisquer benefícios de desempenho com os módulos ES6. Você ainda precisará de uma biblioteca extra para agrupar os módulos, mesmo quando houver suporte completo para os recursos do ES6 no navegador.
fonte
node --experimemntal-modules index.mjs
você pode usarimport
sem o Babel. Você pode (e deve) também publicar seus pacotes npm como ESModule nativo, com compatibilidade com versões anteriores darequire
maneira antiga . Muitos navegadores também suportam importações dinâmicas nativamente.A resposta atual é não, porque nenhum dos mecanismos atuais do navegador é implementado
import/export
no padrão ES6.Alguns gráficos de comparação http://kangax.github.io/compat-table/es6/ não levam isso em consideração. Portanto, quando vir quase todos os greens do Chrome, tenha cuidado.
import
A palavra-chave do ES6 não foi levada em consideração.Em outras palavras, os motores atuais do navegador, incluindo V8 não pode importar novo arquivo JavaScript do arquivo principal JavaScript através de qualquer directiva JavaScript.
(Podemos ainda estar a apenas alguns bugs ou anos até que o V8 implemente isso de acordo com a especificação ES6.)
Este documento é o que precisamos e este documento é o que devemos obedecer.
E o padrão ES6 disse 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
.h
arquivos (cabeçalhos) .Essa é uma estrutura boa e bem testada, e tenho certeza que os especialistas que criaram o padrão ES6 tinham isso em mente.
É isso que permite que o Webpack ou outros pacotes de pacotes otimizem o pacote em alguns casos especiais e reduzam algumas dependências do pacote que não são necessárias. Mas, nos casos em que temos dependências perfeitas, isso nunca acontecerá.
Isso levará algum tempo até que o
import/export
suporte nativo seja ativado e arequire
palavra - chave não vá a lugar algum por um longo período de tempo.O que é
require
?Esta é a
node.js
maneira de carregar módulos. ( https://github.com/nodejs/node )O nó usa métodos no nível do sistema para ler arquivos. Você basicamente depende disso ao usar
require
.require
terminará em algumas chamadas do sistemauv_fs_open
(depende do sistema final, Linux, Mac, Windows) para carregar o arquivo / módulo JavaScript.Para verificar se isso é verdade, tente usar o Babel.js e você verá que a
import
palavra - chave será convertida emrequire
.fonte
import
em um processo de compilação Webpack 2 / Rollup pode reduzir potencialmente o tamanho do arquivo resultante, 'agitando a árvore' módulos / códigos não utilizados, que de outra forma poderiam acabar no pacote final. Tamanho menor do arquivo = mais rápido para baixar = mais rápido para iniciar / executar no cliente.import
palavra - chave nativamente. Ou isso significa que você não pode importar outro arquivo JavaScript de um arquivo JavaScript. É por isso que você não pode comparar os benefícios de desempenho desses dois. Mas é claro que ferramentas como Webpack1 / 2 ou Browserify podem lidar com compactação. Eles são pescoço a pescoço: gist.github.com/substack/68f8d502be42d5cd4942import
eexport
são declarações estáticas que importam um caminho de código específico, enquantorequire
podem ser dinâmicas e, portanto, agrupar o código que não é usado. O benefício de desempenho é indirect-- Webpack 2 e / ou Rollup pode potencialmente resultar em tamanhos de pacote menores que são mais rápidos para download, e, portanto, aparecem snappier para o usuário final (de um navegador). Isso funciona apenas se todo o código for escrito nos módulos ES6 e, portanto, as importações podem ser analisadas estaticamente.import/export
é convertido emrequire
, concedido. Mas o que acontece antes desta etapa pode ser considerado um aprimoramento do "desempenho". Exemplo: selodash
estiver escrito no ES6 e vocêimport { omit } from lodash
, o pacote final conterá SOMENTE 'omitir' e não os outros utilitários, enquanto um simplesrequire('lodash')
importará tudo. Isso aumentará o tamanho do pacote, levará mais tempo para baixar e, portanto, diminuirá o desempenho. Isso é válido apenas no contexto do navegador, é claro.O uso de módulos ES6 pode ser útil para 'trepidação de árvores'; ou seja, habilitar o Webpack 2, Rollup (ou outros empacotadores) 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 o CommonJS é fornecido por padrão porque o Webpack et al não têm como saber se é necessário.
Isso é feito usando a análise estática do caminho do código.
Por exemplo, usando:
... fornece ao bundler uma dica que
package.anotherPart
não é necessária (se não for importada, não pode ser usada - certo?), para não incomodá-lo.Para habilitar isso no Webpack 2, você precisa garantir que seu transpiler não esteja cuspindo módulos CommonJS. Se você estiver usando o
es2015
plug-in com babel, poderá desativá-lo da seguinte.babelrc
maneira:O pacote cumulativo e outros podem funcionar de maneira diferente - visualize os documentos se você estiver interessado.
fonte
Quando se trata de carregamento assíncrono ou talvez lento,
import ()
é muito mais poderoso. Veja quando exigimos o componente de maneira assíncrona, depois o usamos deimport
maneira assíncrona como naconst
variável usingawait
.Ou se você quiser usar
require()
então,A coisa é
import()
realmente assíncrona por natureza. Conforme mencionado por neehar venugopal no ReactConf , você pode usá-lo para carregar dinamicamente componentes de reação 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 faça o download de uma parte necessária quando o usuário se conecta a um site específico ao seu componente específico. por exemplo, a página de login antes do painel não faria o download de todos os componentes do painel. Porque o que é necessário é atual, isto é, o componente de login, que somente será baixado.
O mesmo vale para
export
: ES6export
são exatamente os mesmos que para CommonJSmodule.exports
.NOTA - Se você estiver desenvolvendo um projeto node.js., será necessário usá-lo estritamente,
require()
pois o nó gerará um erro de exceção comoinvalid token 'import'
se fosse usarimport
. Portanto, o nó não suporta instruções de importação.ATUALIZAÇÃO - Conforme sugerido por Dan Dascalescu : Desde a v8.5.0 (lançada em setembro de 2017),
node --experimental-modules index.mjs
você pode usarimport
sem Babel. Você pode (e deve) também publicar seus pacotes npm como ESModule nativo, com compatibilidade com versões anteriores dos antigosrequire
maneira .Veja isso para obter mais informações sobre onde usar importações assíncronas - https://www.youtube.com/watch?v=bb6RCrDaxhw
fonte
O 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 ES6 são suportados por 84% dos navegadores. Enquanto o Node.js os coloca atrás de um sinalizador --experimental-modules , também há um pacote de nós conveniente chamado esm , que facilita a integração.
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
node_modules
diretório, enquanto a maioria dos módulos ES6 é implantada em uma estrutura de diretórios simples. Isso não é fácil de conciliar, mas pode ser feito invadindo seupackage.json
arquivo com scripts de pré e pós-instalação. Aqui está um exemplo de módulo isomórfico e um artigo explicando como ele funciona.fonte
Eu pessoalmente uso a importação porque, podemos importar os métodos necessários, membros usando a importação.
Nome do arquivo : dep.js
O crédito é para Paul Shan. Mais informações .
fonte
require
maneira antiga ?const {a,b} = require('module.js');
funciona tão bem ... se você exportara
eb
module.exports = { a: ()={}, b: 22 }
- A segunda parte da @BananaAcid responesNo momento, na importação do ES6, a exportação é sempre compilada no CommonJS ; portanto, não há benefício em usar um ou outro. Embora o uso do ES6 seja recomendado, pois deve ser vantajoso quando o suporte nativo dos navegadores é lançado. O motivo é que você pode importar parciais de um arquivo enquanto no CommonJS você precisa exigir todo o arquivo.
ES6 →
import, export default, export
CommonJS →
require, module.exports, exports.foo
Abaixo está o uso comum deles.
Padrão de exportação do ES6
O ES6 exporta vários e importa vários
CommonJS module.exports
CommonJS module.exports multiple
fonte
Não sei por que (provavelmente otimização - carregamento lento?) Está funcionando assim, mas notei que
import
talvez não seja possível analisar o código se os módulos importados não forem usados.O que pode não ser o comportamento esperado em alguns casos.
Tome a classe Foo odiada como nossa dependência de amostra.
foo.ts
Por exemplo:
index.ts
index.ts
index.ts
Por outro lado:
index.ts
fonte