Bundlers, Build Tools, Compilers, Transpilers, Parsers, Runtimes…

29/07/2022

Esse post foi escrito há mais de 2 anos

Sempre vale deixar mais claro os nomes e definições para entendermos melhor alguma coisa. Eu particularmente nunca tinha mergulhado a fundo em tentar listar e diferenciar bundlers, build tools, compilers, transpilers, parsers e runtimes... Vamos tentar fazer isso agora

Compilers e Transpilers

Não é muito nítida a diferenciação entre compiler e transpiler no mundo javascript, mas basicamente o que essas ferramentas fazem é transformar código de uma linguagem para outra linguagem. Os principais casos são (i.) converter versões do javascript (ES2022 por exemplo) para versões mais antigas (ES5); (ii.) JSX para Javascript; e (iii.) Typescript para Javascript.

  • Babel - O Babel ficou especialmente famoso quando surgiu o ES6 e JSX. Como a maioria dos runtimes não suportava es6, e até hoje não suportam JSX, o Babel brilhou ali. Mas hoje está sendo substituído por alternativas mais rápidas.
  • SWC - Escrito em Rust, é um compilador mais rápido do que aqueles escritos em JS. É utilizado pelo Next e Parcel.
  • ESBuild - Escrito em Go, o que faz que seja muito rápido também. Snowpack e Vite usam ESBuild.
  • TSC (transpiler do typescript) - é o transpilador/compilador oficial do Typescript.

Build Tools e Bundlers

Build tools / bundlers são ferramentas que conseguem transformar código de desenvolvimento para código de produção. Para isso, é necessário compilar todo o código de diferentes bibliotecas em um único arquivo, ou bundle. Além disso é feito também minificação, e muitas ferramentas trazem também um ambiente de desenvolvimento, com servidor e hot reloading.

  • Gulp e Grunt: build tools que hoje não são mais comumente utilizados Os "precursores" dos build tools modernos.
  • Webpack: O Webpack revolucionou a forma de fazermos bundles dos projetos por permitir que conseguíssemos importar outros tipos de arquivos para o javascript (imagens, svg, css, etc). Mas temos que falar: a API do Webpack é extremamente difícil.
  • Rollup: Maior concorrente do Webpack, a ideia aqui é simplificar a api com ganho de performance também.

Dev Environments

Vou citar aqui dois que são mais "agnósticos", que não estão presos a um framework específico (o que acontece com Next ou create-react-app, por exemplo). Vite é, sem dúvida, o queridinho da comunidade 🙂

Javascript Runtimes:

Um runtime é onde nosso código javascript vai efetivamente rodar. Não podemos pegar um código javascript e fazê-lo funcionar sem termos "onde" fazer funcionar. Geralmente os runtimes além de rodarem o javascript com uma engine (V8, Spidermonkey ou JavascriptCore) trazem algumas APIs/funcionalidades adicionais.

  • Navegador - Originalmente o único lugar em que o JS funcionava era no browser. . Dependendo do navegador, é usado uma "engine" diferente. Por exemplo, no Chrome é o V8. No Firefox é o SpiderMonkey e no Safari é o JavascriptCore
  • NodeJS - em 2009 alguns devs acharam que javascript deveria rodar também fora do navegador. Muita gente, na época, achou a ideia meio besta 🙃. Foi o início da era do JS no servidor. Roda "em cima" do V8.
  • Deno - Em 2018, o mesmo criador do Node criou outro runtime. O Deno fechava alguns "gaps" que o Node havia deixado, e rodar typescript nativamente. As edge functions da netlify rodam no Deno, por exemplo. O Deno também usa o V8
  • Bun - E agora, em 2022, o novo runtime é o Bun, que não usa o V8, mas sim o JavascriptCore (igual o Safari). É criado em uma linguagem chamada zig. Mas o que é diferente aqui, é que o Bun não quer ser apenas um runtime. Ele é também um module bundler, transpiler (typescript e jsx), e web server, tudo ao mesmo tempo.

Javascript Parsers:

Um parser é quem vai transformar javascript em uma "árvore sintática" que é mais "legível" para a máquina. Por exemplo, o ESLint precisa fazer o "parse" do código para que consiga entender o que está acontecendo ali e consiga capturar erros. Mas ele não "roda" efetivamente o código.

Por exemplo, um parser vai transformar um simples 1 + 1 em algo como isso:

Node {
  type: 'Program',
  start: 0,
  end: 5,
  body: [
    Node {
      type: 'ExpressionStatement',
      start: 0,
      end: 5,
      expression: Node {
        type: 'BinaryExpression',
        start: 0,
        end: 5,
        left: Node { type: 'Literal', start: 0, end: 1, value: 1, raw: '1' },
        operator: '+',
        right: Node { type: 'Literal', start: 4, end: 5, value: 1, raw: '1' }
      }
    }
  ],
  sourceType: 'script'
}

Dois famosos parsers existentes é o Acorn e o Espree (do eslint).