Skip to content

Instantly share code, notes, and snippets.

@berardo
Last active February 22, 2022 09:43
Show Gist options
  • Save berardo/d61172d4667781e08bb964459cf22c74 to your computer and use it in GitHub Desktop.
Save berardo/d61172d4667781e08bb964459cf22c74 to your computer and use it in GitHub Desktop.
Resumo geral sobre ES6 Modules - Material complementar dos meus cursos sobre Javascript no Udemy.com (https://www.udemy.com/user/joseberardo/)

ES6 MODULES - RESUMO GERAL

Instruções imports são úteis para linkar módulos (arquivos). Bundlers (ex: Browserify / Webpack) são normalmente acionados para criar um arquivo contendo tudo que foi importado a partir de um arquivo entry point e a ramificação de suas dependências. Loaders são capazes de carregar módulos dinamicamente (ex: O SystemJS é capaz de carregar módulos exportados em qualquer formato: CommonJS, AMD, ES6, variáveis globais e até mesmo módulos paraguaios vindos pela Ponte da Amizade ;)

Obs: Há um projeto chamado SystemJS builder que é um bundler e talvez possamos considerar o Webpack Dev Server um loader que roda dentro um serviço HTTP próprio. Ambos também suportam módulos não ES6.

Apesar se ser possível carregar módulos dinamicamente, a especificação ES6 modules determina que elas são instruções declarativas, sendo obrigatoriamente realizadas antes do script iniciar. Isso traz diversas vantagens, a mais notada delas é a Treek Shaking.

Import nomeado

Ao utilizar chaves, como em:

import { Message } from './message.model';

Estamos importando alguma constante / variável / função / classe que foi exportada sem a instrução default. Ex: export class Message { }

Ao contrário de módulos CommonJS, ES6 imports importam os chamados immutable bindings, ou seja referências imutáveis ao que foi exportado no módulo em questão. Assim, todas as alterações realizadas posteriormente (como através de timeouts ou eventos por exemplo) são automaticamente refletidas no módulo que importou e vice-versa.

Import não nomeado

Ao utilizar imports sem chaves, como em:

import Message from './message.model';

Estamos importando o único elemento exportado através da instrução export default. Neste caso, qualquer valor pode ser exportado. Por exemplo (três exemplos distintos, não podem estar presentes no mesmo arquivo):

  • export default { esse: 'objeto', foi: 'exportado' };
  • export default 'essa string também';
  • export default variavelDeclaradaAnteriormente;

Por ser possível exportar de modo default qualquer valor literal, só é possível have um único export default por arquivo. Do contrário não haveria como saber o que importar na outra ponta.

Import renomeado

É possível ainda (re)definir o nome do que foi importado como em:

  • import { Message as MessageModel } from './message.model';
  • import { default as MessageModel } from './message.model';
  • import * as TudoQueVemDeLa from './la/do/outro/lado';

Acima, a primeira linha importou algo chamado Message em message.model.js mas resolveu chamar de MessageModel. Já a segunda linha importou o export default de message.model.js não importa qual nome foi utilizado para referenciar o valor a ser exportado, nem mesmo se houve algum. Essa linha é equivalente a (perceba a ausência das chaves nesse caso):

import MessageModel from './message.model';

Já na terceira linha do bloco anterior, TudoQueVemDeLa colecionará todos os exports do módulo em questão, além do atributo default referenciando o valor exportado através de export default, caso haja. O comando import * exige o complemento as algumaCoisa.

Import geral

Ao utilizar imports sem informar como queremos tratar o que será importado, como em:

import './criar-listeners';

Não estamos interessados em nada que possa ter sido exportado na outra ponta, mas sim interessados em apenas executar o arquivo em questão. Não é a melhor prática, mas pode servir para importar código legado. Declarações top level do arquivo importado ficarão disponíveis no arquivo corrente.

Desta forma, podemos importar outros formatos como:

import './styles/header.css';

obs: Loaders/bundlers como o Webpack (através do Styles Loader) entendem esse import como instrução para injetar uma tag style no documento de entrada (entry point) e carregar o estilo do arquivo importado.

Após a cláusula from definimos o caminho para um arquivo ou módulo instalado no diretório node_modules. Caso o valor não inicie com algo que denuncie um caminho (como ., .. ou /), em geral bundlers entendem como referência a node_modules.

Re-exporting

Ainda é possível importar e exportar ao mesmo tempo:

export { Message as MessageModel } from './message.model';

Perceba a semelhança desse export com relação a um comando import. Desde que você não precise localmente do que está referenciando, é possível repassá-lo para outro módulo.

Múltiplos imports

É possível importar diversas coisas na mesma linha:

  • import { Message, ImageMessage } from './messages-modules'
  • import VouChamarODefaultDeMessage, { OutraCoisaNaoDefault as UmNomeQualquer } from './qualquer-lugar';

Essa prática vem se tornando cada vez mais frequente e é bem mais recomendável do que imports com asteriscos porque permitem a seleção específica do que se quer importar. A técnica conhecida como Tree Shaking, introduzida pelo Rollup mas também disponível no Webpack 2 garantem bundles contendo unicamente o que se quer do módulo que foi importado, dispensando todo o resto do conteúdo do arquivo. Isso proporciona um bundle final bem mais enxuto.

System.import

A especificação para ES6 modules trata ainda da capacidade de realizar importações dinâmicas. Em geral, elas são menos recomendáveis, uma vez que dificultam a análise estática das dependências (imagine que possam vir dentro de uma função ou desvio condicional, o que acabaria forçando o bundler / loader a executar os cenários possíveis pra decidir se carrega o módulo importado ou não).

De qualquer forma, é possível utilizar a instrução System.import('./caminho/pro/meu/modulo') que retorna uma promise que uma vez o módulo sendo carregado, resolve (then) e recupera os valores exportados.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment