WDD 231: Desenvolvimento Frontend para Web I

S03 - Atividades de Aprendizagem: Módulos JavaScript

Visão Geral

Você já deve ter visto ou escrito código JavaScript que é longo e difícil de ler. Isso geralmente é resultado do desenvolvimento de código em um único arquivo. Isso dificulta a manutenção e o entendimento, principalmente quando o projeto se torna maior e mais complexo. Para resolver esse problema, os Módulos ES JavaScript (ECMAScript Modules) foram introduzidos para fornecer uma maneira de organizar o código em partes menores e reutilizáveis, chamadas módulos.

Preparação

Os módulos oferecem maneiras de ajudar você a escrever código de forma mais clara, organizada e controlável, dividindo-o em partes menores e reutilizáveis. As seções adiante abordam os principais conceitos e motivos de como e por que usar módulos.

Suporte Nativo do Navegador

Para usar os recursos de um módulo, é necessário que a tag <script> contenha o atributo type="module". Esse atributo informa ao navegador para considerar o script como um módulo, permitindo o uso de instruções import e export dentro do script.

Por exemplo, você faria referência a um script de módulo chamado app assim:

<script type="module" src="scripts/app.mjs"></script>

Observe que o arquivo de script usa a extensão .mjs para indicar que é um módulo. Embora não seja estritamente necessário, seu uso é considerado uma boa prática para clareza e consistência ao trabalhar com Módulos ES.

Os módulos são carregados de forma assíncrona por padrão, assim não bloqueiam o interpretador HTML durante o carregamento ou execução. Dessa forma, não há necessidade de adicionar o atributo defer às referências de script do módulo.

Melhor Organização de Código

Os módulos permitem que você divida seu código em diferentes arquivos. Isso permite que você tenha uma melhor organização do código, pois mantém a funcionalidade relacionada junta e separa o código não relacionado. Por exemplo, você pode ter um módulo para manipular o DOM e outro módulo para gerenciar o armazenamento de dados.

Os módulos podem ter funções export e import, objetos ou variáveis entre diferentes arquivos. Por exemplo, você pode ter um módulo para renderizar fichas de produtos e outro módulo para gerenciar o armazenamento de dados.

Observe esse exemplo. Temos três arquivos de módulo: armazenamento.mjs, resultado.mjs e app.mjs. Cada módulo tem sua própria responsabilidade e pode ser importado conforme necessário.

Esse é o módulo armazenamento.mjs que exporta uma função, uma variável e uma classe. A palavra chave export permite que outros módulos importem para dentro deles esses códigos e os utilizem.

// em armazenamento.mjs - lida com gerenciamento de dados
export function obterDados() { /* implementação */ }
export total;
export default class GerenciadorDeArmazenamento { /* implementação */ }

Esse é o módulo resultado.mjs que exporta uma função para renderizar a interface do usuário.

// em resultado.mjs - processa a renderização da IU
export default function renderizarFichaDoProduto() { }

Esse é o módulo app.mjs que importa e usa ambos os módulos. A instrução import traz funcionalidades de outros módulos para dentro dele para utilizá-los.

// em app.mjs - importa e usa ambos os módulos
import { obterDados, total } from './armazenamento.mjs';
import GerenciadorDeArmazenamento from './armazenamento.mjs';
import renderizarFichaDoProduto from './resultado.mjs';

Cada módulo pode ter várias exportações nomeadas e uma exportação padrão.

As exportações nomeadas permitem que você exporte vários valores de um módulo. Você deve importá-los usando o mesmo nome dentro de chaves.

As exportações padrão são úteis para a função ou classe principal de um módulo. São aquelas que usam a palavra chave export default antes de sua declaração, e são importadas sem o uso de chaves, como nos exemplos acima.

Os módulos podem ser importados em qualquer ordem, e o sistema de módulos garante que as dependências sejam resolvidas corretamente.

Os módulos têm escopo local, ou seja, variáveis e funções definidas em um módulo não são acessíveis em outros módulos, a menos que sejam exportadas explicitamente. Isso ajuda a evitar conflitos de nomenclatura e mantém o escopo global organizado.

Reutilização

Os módulos podem ser reutilizados em diferentes partes da sua aplicação ou até mesmo em diferentes projetos. Isso promove a reutilização de código e reduz a duplicação, facilitando a manutenção e a atualização da sua base de código.

Por exemplo, se você tiver um módulo que lida com autenticação do usuário, poderá usá-lo em várias aplicações sem precisar reescrever o código. Isso é principalmente útil para bibliotecas ou estruturas que fornecem funcionalidades comuns que podem ser compartilhadas entre diferentes projetos.

Ao usar módulos, você pode criar uma biblioteca de componentes reutilizáveis que podem ser facilmente importados e usados em outras partes da sua aplicação. Além de economizar tempo, isso ajuda a manter sua base de código organizada.

Instruções da Atividade

Nesta atividade, você substituirá a estrutura da aplicação existente por uma que use módulos.

Inspecione

  1. Abra a página modulos.html e visualize/inspecione o HTML e o JavaScript.
  2. Observe que há apenas um arquivo JavaScript chamado modulos.js.
  3. Revise o código. Este código será colocado em módulos.

    Observe que o elemento <form> não é usado para a entrada de dados. Isso porque um formulário (form) faz com que a página seja recarregada quando o botão for clicado, e esse não é um comportamento desejado neste caso. Em vez disso, o botão é usado para executar as funções matricularEstudante() e removerEstudante() por meio de receptores de eventos. Um elemento <form> poderia ser usado, mas o comportamento padrão do formulário precisaria ser alterado (ignorado) usando o método event.preventDefault().

Configuração e Estrutura

  1. Crie seus próprios arquivos modulos.html, modulos.css, modulos.mjs e copie o HTML, CSS e JavaScript fornecidos na etapa 1.
  2. Crie um novo arquivo JavaScript chamado curso.mjs.
  3. Crie um novo arquivo JavaScript chamado secoes.mjs.
  4. Crie um novo arquivo JavaScript chamado modulos-solucao.mjs

curso

Este arquivo conterá os dados da seção do objeto do curso e seus métodos que são usados para matricular e remover estudantes do curso.

  1. Mova o objeto cursoBYUI do arquivo modulos.js para o arquivo curso.mjs.
  2. No arquivo curso.mjs exporte (export) o objeto cursoBYUI comom padrão (default). Esta linha pode ser a última linha do arquivo.
    export default cursoBYUI;

secoes

Este arquivo conterá a função que preenche o elemento de seleção de seção na página.

  1. Mova a função definirSecaoSelecionada do arquivo modulos.js para o arquivo secoes.mjs.
  2. exporte (export) a função definirSecaoSelecionada como uma exportação explícita (named export).
    export function definirSecaoSelecionada(secoes) { ... }
  3. Por fim, remova a linha de código renderizarSecoes(this.secoes); no método mudarMatricula do objeto cursoBYUI. Um erro de tempo de execução ocorrerá durante uma tentativa de atualização, pois essa função não estará mais disponível para chamada neste novo arquivo de módulo.

solução

Este arquivo conterá as funções usadas para renderizar o título do curso e as seções na página.

  1. Mova as funções definirTitulo e renderizarSecoes para o arquivo modulos-solucao.mjs.
  2. exporte (export) as funções definirTitulo e renderizarSecoes como exportações explícitas.
    export function definirTitulo(curso) { ... }
    export function renderizarSecoes(secoes) { ... }

módulos

O conteúdo deste arquivo de script foi reduzido a receptores de eventos e chamadas de função.

  1. Na parte superior do arquivo, importe (import) o objeto cursoBYUI do módulo curso.
    import cursoBYUI from './curso.mjs';
  2. Em seguida, importe (import) a função definirSecaoSelecionada do módulo secoes.
    import { definirSecaoSelecionada } from './secoes.mjs';

    Observe que a função está entre colchetes porque é uma exportação explícita (named export). Os colchetes não são necessários para uma única importação, mas são recomendados para maior clareza. Esta função não é a exportação padrão do módulo. Ela pode ser convertida em uma exportação padrão no módulo, mas isso não é necessário.

  3. Em seguida, importe (import) as exportações de função nomeadas do arquivo modulos-solucao.mjs.
    Avalie Seu Conhecimento
    import { definirTitulo, renderizarSecoes } from "./modulos-solucao.mjs";

    Observe que as duas funções estão entre colchetes e separadas por uma vírgula.

  4. Adicione renderizarSecoes(cursoBYUI.secoes); para ambos os receptores de eventos, a fim de atualizar a saída depois que o botão de matricular ou remover for clicado.
    document.querySelector("#matricularEstudante").addEventListener("click", função () {
      const numSecao = document.querySelector("#numSecao").value;
      cursoBYUI.mudarMatricula(numSecao);
      renderizarSecoes(cursoBYUI.secoes);
    });
            
    document.querySelector("#removerEstudante").addEventListener("click", function () {
      const numSecao = document.querySelector("#numSecao").value;
      cursoBYUI.mudarMatricula(numSecao, false);
      renderizarSecoes(cursoBYUI.secoes);
    });

Script HTML

  1. Altere a referência de script no arquivo modulos.html para usar a nova estrutura de módulo, removendo o atributo defer e adicionando o atributo type="module".
    <script type="module" src="scripts/modulos.js"></script>

Teste e Compartilhe

  1. Teste seu código para garantir que ele funcione conforme o esperado. Você deve conseguir selecionar uma seção e aumentar ou diminuir o total de matrículas exibido para a seção selecionada.
  2. Compartilhe seu código e possíveis problemas com seus colegas no Microsoft Teams para revisão.

Recursos Opcionais