ECMAScript 2015: Módulos

ES2015 Gotchas é uma série quinzenal sobre as novidades e pegadinhas do ES2015.

Até sua especificação anterior, Javascript não tinha um modelo padrão de criação e utilização de módulos/libs, e para suprir essa necessidade surgiram alguns padrões diversos utilizados aqui e ali, como o CommumJS adotado pelo NodeJS e o AMD (Asynchronous Module Definition) implementado pelo RequireJS, entre outros.

Mas se o problema já foi resolvido, talvez nem fosse necessário uma solução da própria linguagem, né? Hoje em dia JavaScript é a linguagem mais utilizada no github e no mundo opensource, e quando criamos alguma lib/componente interessante e queremos compartilhar, queremos que todos possam utilizar, independente de sua arquitetura. Porem para isso precisamos nos prevenir para todos esses diversos padrões que estão por ai, cada uma de suas particularidades, adicionando mais uma camada de complexidade, mais testes, mais trabalho.

Agora imagine que todos possam simplesmente fazer isso:

// lib/math.js
export function sum(x, y) {  
  return x + y;
}
export default 3.141593;  
import pi, {sum} from "lib/math";

console.log("2π = " + sum(pi, pi));

if(true) {  
  import * as myModule from "anything";
  // throw error, já vamos falar sobre isso...
}

Análise estática de dependências

Todos os modelos atuais compartilham o fato de serem dinâmicos, sendo analisados em tempo de execução e terem problemas com referências circulares, independente de serem síncronos ou assíncronos.

Com a lição aprendida com as deficiências dos padrões atuais, a especificação do Javascript adotou uma abordagem diferente, que não poderia ser adotada por nenhum outro modelo que não seja da própria linguagem: análise estática de dependências. Isso significa que todas as dependências serão analisadas e resolvidas antes da execução do código, e toda a exportação ou importação de módulos deverá estar no primeiro nível de instruções, e qualquer tentativa de fazê-lo dentro de um try/catch, função, condição ou looping, resultará em um erro ainda no momento de resolução das dependências, antes de sua execução.

Pode parecer estranho que uma linguagem dinâmica escolha uma abordagem modular estática, e com certeza existirão casos em que uma abordagem dinâmica será necessária, mas para essas exceções os modelos atuais já resolvem e ainda poderão ser utilizados, mas agora temos outros benefícios que não tínhamos a nossa disposição, como a solução definitiva para dependências circulares e possibilidade de um melhor suporte ferramental.

Importação parcial de dependências

Um módulo pode exportar quantas funções, objetos e variáveis quiser, quando for utilizá-lo podemos especificar apenas o que queremos, além de facilitar a escrita e leitura do código, também possibilita a geração de bundles de código menores apenas com a parte que precisa de suas dependências e sem carregar código morto que não sera utilizado em nenhum momento na sua aplicação.

Implicitamente assíncrono

De bônus, a partir da análise estática de dependências, antes mesmo da execução do código, ganhamos também a possibilidade de carregamento assíncrono das dependências, mas com uma sintaxe de código elegante sem necessidade de callbacks ou qualquer outro artifício.

Lembrando que essa série não deseja ser uma referência definitiva de cada uma das novas funcionalidades do ES2015, mas sim de nossos aprendizados nas questões mais pegajosas de cada uma. Caso queira saber mais detalhes de implementação de módulos sugerimos o ótimo artigo da Mozzila (em inglês).

Até a próxima! Fiquem ligados na série ES2015 Gotchas!

William Grasel

Read more posts by this author.