Articles

Configurando um Projeto ES6 Usando Babel e webpack

Neste artigo, vamos analisar a criação de uma configuração de compilação para lidar com JavaScript moderno (rodando em navegadores web) usando Babel e webpack.

Isso é necessário para garantir que nosso código JavaScript moderno em particular seja compatível com uma gama mais ampla de navegadores do que poderia ser de outra forma.

JavaScript, como a maioria das tecnologias relacionadas à web, está evoluindo o tempo todo. Nos bons velhos tempos, podíamos deixar cair um par de <script> tags numa página, talvez incluir jQuery e um par de plugins, então seria bom ir.

No entanto, desde a introdução do ES6, as coisas têm-se tornado progressivamente mais complicadas. O suporte ao navegador para novas funcionalidades da linguagem é frequentemente irregular, e à medida que os aplicativos JavaScript se tornam mais ambiciosos, os desenvolvedores estão começando a usar módulos para organizar seu código. Por sua vez, isso significa que se você está escrevendo JavaScript moderno hoje, você precisará introduzir um passo de compilação em seu processo.

Como você pode ver nos links abaixo, a conversão do ES6 para ES5 aumenta drasticamente o número de navegadores que podemos suportar.

>

  • compatibilidadeES6
  • compatibilidadeES5

O propósito de um sistema de compilação é automatizar o fluxo de trabalho necessário para ter nosso código pronto para os navegadores e produção. Isto pode incluir passos como a transposição do código para um padrão diferente, compilação de Sass para CSS, empacotamento de arquivos, código de minificação e compressão, e muitos outros. Para assegurar que estes sejam consistentemente repetíveis, um sistema de compilação é necessário para iniciar os passos numa sequência conhecida a partir de um único comando.

Prerequisites

A fim de seguir em frente, você precisará ter ambos Node.js e npm instalados (eles vêm empacotados juntos). Eu recomendaria usar um gerenciador de versão como o nvm para gerenciar sua instalação do Node (aqui está como), e se você gostaria de alguma ajuda para aprender a lidar com o npm, então veja o tutorial de npm do SitePoint para iniciantes.

Set Up

Criar uma pasta raiz em algum lugar no seu computador e navegar para ela a partir do seu terminal/linha de comando. Este será seu arquivo <ROOT> pasta.

Crie um arquivo package.json com isto:

npm init -y

Nota: O sinalizador -y cria o arquivo com as configurações padrão, e significa que você não precisa completar nenhum dos detalhes usuais da linha de comando. Eles podem ser alterados no seu editor de código mais tarde se você desejar.

Na sua pasta <ROOT>, faça os diretórios src, src/js, e public. A pasta src/js será onde colocaremos nosso código fonte não processado, e a pasta public será onde o código transposto terminará.

Transpiling with Babel

Para começar, vamos instalar o babel-cli, que fornece a capacidade de transpor o ES6 para o ES5, e o babel-preset-env, que nos permite direcionar versões específicas do navegador com o código transposto.

npm install babel-cli babel-preset-env --save-dev

Você deve agora ver o seguinte no seu arquivo package.json:

"devDependencies": { "babel-cli": "^6.26.0", "babel-preset-env": "^1.6.1"}

Aonde quer que estejamos no arquivo package.json, vamos mudar a seção scripts para ler assim:

"scripts": { "build": "babel src -d public"},

Isso nos dá a habilidade de chamar Babel através de um script, em vez de diretamente do terminal toda vez. Se você gostaria de saber mais sobre scripts npm e o que eles podem fazer, veja este tutorial do SitePoint.

Por último, antes de podermos testar se o Babel está fazendo sua coisa, precisamos criar um arquivo de configuração .babelrc. É a isso que nosso pacote babel-preset-env se referirá para seus parâmetros de transpile.

Crie um novo arquivo no seu diretório <ROOT> chamado .babelrc e cole o seguinte nele:

{ "presets": } } ] ]}

Isso configurará o Babel para transpile para as duas últimas versões de cada navegador, mais o Safari na v7 ou superior. Outras opções estão disponíveis dependendo de quais navegadores você precisa suportar.

Com isso salvo, agora podemos testar as coisas com um arquivo JavaScript de exemplo que usa ES6. Para os propósitos deste artigo, eu modifiquei uma cópia do leftpad para usar a sintaxe do ES6 em vários lugares: literal dos modelos, funções de seta, const e let.

Salve isto como src/js/leftpad.js e a partir do seu terminal execute o seguinte:

npm run build

Se tudo estiver como pretendido, na sua pasta public deverá agora encontrar um novo ficheiro chamado js/leftpad.js. Se o abrir, verá que já não contém mais nenhuma sintaxe ES6 e fica assim:

Organizar o seu Código com Módulos ES6

Um módulo ES6 é um ficheiro JavaScript que contém funções, objectos ou valores primitivos que deseja disponibilizar para outro ficheiro JavaScript. Você export de um, e import para o outro. Qualquer projecto JavaScript moderno sério deve considerar a utilização de módulos. Eles permitem que você quebre seu código em unidades autônomas e, assim, tornar as coisas mais fáceis de manter; eles ajudam a evitar a poluição do namespace; e ajudam a tornar seu código mais portátil e reutilizável.

Se a maioria da sintaxe do ES6 estiver amplamente disponível nos navegadores modernos, este ainda não é o caso dos módulos. No momento da escrita, eles estão disponíveis em Chrome, Safari (incluindo a última versão do iOS) e Edge; estão escondidos atrás de uma bandeira no Firefox e Opera; e não estão disponíveis (e provavelmente nunca estarão) no IE11, nem na maioria dos dispositivos móveis.

Na próxima secção, vamos ver como podemos integrar módulos na nossa configuração de compilação.

Exportar

A palavra-chave export é o que nos permite tornar os nossos módulos ES6 disponíveis para outros ficheiros, e dá-nos duas opções para o fazer – named e default. Com a exportação nomeada, você pode ter múltiplas exportações por módulo, e com uma exportação padrão você tem apenas uma por módulo. Exportações nomeadas são particularmente úteis onde você precisa exportar vários valores. Por exemplo, você pode ter um módulo contendo um número de funções utilitárias que precisam estar disponíveis em vários lugares dentro de seus aplicativos.

Então vamos transformar nosso arquivo leftPad em um módulo, que podemos então requerer em um segundo arquivo.

Named Export

Para criar uma exportação nomeada, adicione o seguinte na parte inferior do leftPad ficheiro:

export { leftPad };

Também podemos remover a declaração "use strict"; do topo do ficheiro, uma vez que os módulos correm em modo estrito por defeito.

Exportação de Defeitos

Como há apenas uma única função a ser exportada no ficheiro leftPad, pode ser um bom candidato para usar export default em vez disso:

export default function leftPad(str, len, ch) { ...}

Again, pode remover a declaração "use strict"; do topo do ficheiro.

Importar

Para fazer uso dos módulos exportados, agora precisamos importá-los para o arquivo (módulo) que desejamos usar em.

Para a opção export default, o módulo exportado pode ser importado com qualquer nome que você desejar escolher. Por exemplo, o módulo leftPad pode ser importado como so:

import leftPad from './leftpad';

Or pode ser importado como outro nome, como so:

import pineapple_fritter from './leftpad';

Funcionalmente, ambos funcionarão exatamente da mesma forma, mas obviamente faz sentido usar ou o mesmo nome que foi exportado sob, ou algo que torne a importação compreensível – talvez onde o nome exportado chocaria com outro nome de variável que já existe no módulo receptor.

Para a opção de exportação nomeada, devemos importar o módulo usando o mesmo nome com o qual ele foi exportado. Para o nosso módulo de exemplo, nós o importaríamos de uma maneira similar à que usamos com a sintaxe export default, mas neste caso, devemos embrulhar o nome importado com chaves de caracóis:

import { leftPad } from './leftpad';

As chaves são obrigatórias com uma exportação nomeada, e falhará se elas não forem usadas.

É possível mudar o nome de uma exportação nomeada na importação se necessário, e para isso, precisamos modificar um pouco nossa sintaxe usando uma sintaxe import as . Como com export, há uma variedade de maneiras de fazer isso, todas detalhadas na página de importação MDN.

import { leftPad as pineapple_fritter } from './leftpad_es6';

Again, a mudança de nome é um pouco disparatada, mas ilustra o ponto de que eles podem ser mudados para qualquer coisa. Você deve manter boas práticas de nomenclatura em todos os momentos, a menos, é claro, que você esteja escrevendo rotinas para preparar receitas baseadas em frutas.

Consumindo o módulo Exportado

Para fazer uso do módulo Exportado leftPad, eu criei o seguinte arquivo index.js na pasta src/js. Aqui, eu faço um loop através de um array de números de série, e prefixo-os com zeros para torná-los em uma string de oito caracteres. Mais tarde, faremos uso disto e os colocaremos em uma lista ordenada de elementos em uma página HTML. Note que este exemplo usa a sintaxe padrão de exportação:

Como fizemos anteriormente, execute o script de compilação a partir do diretório <ROOT>:

npm run build

Babel irá agora criar um arquivo index.js no diretório public/js. Como no nosso arquivo leftPad.js, você deve ver que Babel substituiu toda a sintaxe do ES6 e deixou para trás apenas a sintaxe ES5. Você também pode notar que ele converteu a sintaxe do módulo ES6 para a sintaxe baseada em Nodos module.exports, o que significa que podemos executá-lo a partir da linha de comando:

node public/js/index.js// 

O seu terminal deve agora fazer log out de um array de strings prefixadas com zeros para torná-las todas de oito caracteres. Com isso feito, é hora de dar uma olhada no webpack.

Introduzindo o webpack e integrando-o com Babel

Como mencionado, os módulos ES6 permitem que o desenvolvedor do JavaScript quebre seu código em pedaços gerenciáveis, mas a conseqüência disso é que esses pedaços têm que ser ser servidos até o navegador solicitante, potencialmente adicionando dezenas de pedidos HTTP adicionais de volta ao servidor – algo que realmente deveríamos estar procurando evitar. É aqui que entra o webpack.

webpack é um bundler de módulos. Seu objetivo principal é processar sua aplicação rastreando todas as suas dependências, e depois empacotá-las todas em um ou mais pacotes que podem ser executados no navegador. No entanto, pode ser muito mais do que isso, dependendo de como é configurado.

configuração dowebpack é baseada em quatro componentes-chave:

  • um ponto de entrada
  • uma localização de saída
  • loaders
  • plugins

Entry: Isto guarda o ponto de início da sua aplicação de onde o webpack pode identificar suas dependências.

Output: Isto especifica onde você gostaria que o pacote processado fosse salvo.

Loaders: Estes são uma forma de converter uma coisa como entrada e gerar algo mais como saída. Eles podem ser usados para estender as capacidades do webpack para lidar com mais do que apenas arquivos JavaScript e, portanto, convertê-los em módulos válidos também.

Plugins: Estes são usados para estender as capacidades do webpack para outras tarefas além do empacotamento – tais como a minificação, a impressão e a otimização.

Para instalar o webpack, execute o seguinte a partir do seu diretório <ROOT>:

npm install webpack webpack-cli --save-dev

Esta instalação do webpack localmente para o projeto, e também dá a capacidade de executar o webpack a partir da linha de comando através da adição de webpack-cli. Você deve agora ver o webpack listado no seu arquivo package.json. Enquanto estiver nesse ficheiro, modifique a secção de scripts da seguinte forma, para que agora saiba usar o webpack em vez do Babel directamente:

"scripts": { "build": "webpack --config webpack.config.js"},

Como pode ver, este script está a chamar num ficheiro webpack.config.js, por isso vamos criar isso no nosso directório <ROOT> com o seguinte conteúdo:

Este é mais ou menos o ficheiro de configuração mais simples que precisa com o webpack. Você pode ver que ele usa as seções de entrada e saída descritas anteriormente (ele poderia funcionar apenas com estas), mas também contém um arquivo mode: 'development' setting.

webpack tem a opção de usar os modos “desenvolvimento” ou “produção”. Configuração mode: 'development' otimiza para velocidade de compilação e depuração, enquanto mode: 'production' otimiza para velocidade de execução em tempo de execução e tamanho do arquivo de saída. Há uma boa explicação dos modos no artigo do Tobias Koppers “webpack 4: mode and optimization” caso deseje ler mais sobre como eles podem ser configurados além das configurações padrão.

Next, remova quaisquer arquivos da pasta public/js. Depois reexecute isto:

npm run build

Vai ver que agora contém um único ficheiro ./public/bundle.js. Abra o novo ficheiro, no entanto, e os dois ficheiros com que começámos parecem bastante diferentes. Esta é a secção do ficheiro que contém o código index.js. Apesar de ter sido bastante modificado a partir do nosso original, ainda pode escolher os seus nomes de variáveis:

Se correr node public/js/bundle.js a partir da pasta <ROOT>, verá que obtém os mesmos resultados que tínhamos anteriormente.

Transpiling

Como mencionado anteriormente, os carregadores permitem-nos converter uma coisa noutra. Neste caso, queremos que o ES6 seja convertido em ES5. Para fazer isso, vamos precisar de mais alguns pacotes:

npm install babel-loader babel-core --save-dev

Para utilizá-los, o webpack.config.js precisa de uma seção de módulos adicionando a ele após a seção de saída, como assim:

Isto usa uma instrução regex para identificar os arquivos JavaScript a serem transpostos com o babel-loader, enquanto exclui qualquer coisa na pasta node_modules disso. Finalmente, o babel-loader é dito para usar o pacote babel-preset-env instalado anteriormente, para estabelecer os parâmetros do transpile definidos no ficheiro .babelrc.

Com isso feito, pode voltar a executar isto:

npm run build

Depois verifique o novo public/js/bundle.js e verá que todos os vestígios da sintaxe do ES6 desapareceram, mas continua a produzir a mesma saída que anteriormente.

Bringing It to the Browser

Aparar construir um webpack funcional e configurar Babel, é hora de trazer o que fizemos para o navegador. Um pequeno arquivo HTML é necessário, e isto deve ser criado na pasta <ROOT> como abaixo:

Um pouco mais de JavaScript é necessário para exibir a lista, então vamos alterar ./src/js/index.js para fazer isso acontecer:

Agora, se você abrir index.html no seu navegador, você deve ver uma lista ordenada aparecer, assim:

Continuando

Como configurado acima, nosso sistema de construção está praticamente pronto para ir. Agora podemos usar o webpack para agregar nossos módulos e transportar o código ES6 até ES5 com Babel.

>

No entanto, é um pouco complicado que, para transportar nosso código ES6, tenhamos que executar npm run build toda vez que fizermos uma mudança.

Adicionando um ‘watch’

Para superar a necessidade de executar repetidamente npm run build, você pode configurar um 'watch' em seus arquivos e ter o webpack recompilar automaticamente toda vez que vir uma alteração em um dos arquivos na pasta ./src. Para implementar isso, modifique a secção scripts do ficheiro package.json, como abaixo:

"scripts": { "watch": "webpack --watch", "build": "webpack --config webpack.config.js"},

Para verificar se está a funcionar, corra npm run watch a partir do terminal, e verá que já não regressa ao prompt de comandos. Agora volte para src/js/index.js e adicione um valor extra no array serNos e salve-o. O meu agora parece com isto:

const serNos = ;

Se você agora verificar o terminal, você verá que ele está desconectado, e que ele voltou a executar o webpack build task. E ao voltar ao navegador e refrescar, você verá o novo valor adicionado ao final da lista, tendo sido processado com leftPad.

Refrescar o navegador automaticamente

Seria muito bom agora se pudéssemos fazer com que o webpack atualizasse o navegador automaticamente toda vez que fizéssemos uma mudança. Vamos fazer isso instalando um pacote npm adicional chamado webpack-dev-server. Não se esqueça de Ctrl + c da tarefa watch primeiro, no entanto!

npm install webpack-dev-server --save-dev

Com isso feito, vamos adicionar um novo script ao arquivo package.json para chamar o novo pacote. A seção scripts agora deve conter isto:

Note a bandeira --open-page adicionada ao final do script. Isto diz webpack-dev-server para abrir uma página específica em seu navegador padrão usando seu modo iframe.

Executar agora npm start e você deve ver uma nova aba do navegador sendo aberta em com a lista de partes sendo exibida. Para mostrar que o 'watch' está funcionando, vá para src/js/index.js e adicione outro novo valor ao final do array serNos. Quando você salvar suas alterações, você deve notá-las refletidas quase imediatamente no navegador.

Com isto completo, a única coisa que resta é que o modo em webpack.config.js seja definido para production. Uma vez isso definido, o webpack também irá minificar o código que sai em ./public/js/bundle.js. Você deve notar que se o mode não estiver definido, o webpack irá usar por padrão o production config.

Conclusion

Neste artigo, você viu como configurar um sistema de compilação para JavaScript moderno. Inicialmente, isto usou Babel a partir da linha de comando para converter a sintaxe do ES6 para ES5. Você então viu como fazer uso dos módulos ES6 com as palavras-chave export e import, como integrar o webpack para executar uma tarefa de agrupamento, e como adicionar uma tarefa de relógio para automatizar a execução do webpack cada vez que forem detectadas alterações no arquivo fonte. Finalmente você viu como instalar webpack-dev-server para atualizar a página automaticamente toda vez que uma alteração é feita.

Se você quiser levar isso adiante, eu sugeriria ler o mergulho profundo do SitePoint no webpack e no empacotamento de módulos, bem como pesquisar carregadores e plugins adicionais que permitirão ao webpack lidar com tarefas de compressão de recursos e Sass. Olhe também para o eslint-loader e o plugin para Prettier também.

Acoplamento feliz …