Minificador de JavaScript

Comprima código JavaScript removendo comentários, espaços e caracteres desnecessários.

Sobre a minificação JavaScript

JavaScript é o tipo de recurso mais pesado na maioria das páginas web, e não apenas porque tende a ser o maior arquivo. O custo é dividido em cinco etapas: download (pela rede), parsing (o motor lê os bytes e constrói uma AST), compilação (V8 ou JavaScriptCore compila a AST em bytecode), execução (o bytecode roda) e, em visitas seguintes, partida quente a partir do bytecode em cache se o motor o manteve. Brotli na borda do CDN cuida do custo de download. A minificação também ajuda no download, mas também ajuda no parsing e compilação em cada dispositivo que baixa seu script, e em um celular Android de gama baixa, parsing e compilação podem demorar mais do que a transferência de rede. Os artigos Cost of JavaScript de Addy Osmani mostraram repetidamente que o que parece um problema de rede muitas vezes é um problema de CPU, e que a redução de 20-40% em bytes via minificação traduz-se de forma bastante direta em milissegundos economizados de tempo de parsing na cauda longa de dispositivos lentos.

A otimização de parsing preguiçoso do V8 adia o parsing completo de qualquer função até que ela seja realmente chamada, o que significa que um script grande com muitas funções não usadas custa menos do que sua contagem de bytes sugere. O cache HTTP do Chrome também armazena o bytecode V8 (o "Code Cache") para que visitas repetidas pulem inteiramente a etapa de parsing e compilação. Nada disso muda a equação básica: scripts menores chegam ao cache quente mais rápido, fazem parsing mais rápido no caminho frio e compilam mais rápido. A minificação é o lugar mais barato em toda a pilha para recuperar milissegundos.

Os quatro (ou cinco) níveis de minificação JavaScript

Nem todos os minificadores são iguais, e o nível que você precisa depende da sua base de código. Nível 1: remoção de espaços e comentários. A passagem mais simples, retirar espaços, tabulações, quebras de linha e comentários // ... / /* ... */. É o que uma passagem por regex pode fazer com segurança (com cuidado em torno de strings, template literals e regex literals). Redução típica: 20-40% em bytes brutos. Nível 2: renomeação de símbolos (mangling). Nomes de variáveis locais, parâmetros de função e (com cuidado) nomes de função são reescritos em letras únicas: function calculateTotal(itemList) torna-se function a(b). Isso requer uma Árvore de Sintaxe Abstrata e análise completa de escopo para saber quais nomes são seguros para renomear, nomes globais, exports, referências às propriedades de this, e tudo que é acessado via chave de string (obj['name']) devem permanecer intactos. Redução adicional típica: 10-25%. Nível 3: eliminação de código morto (tree shaking). Análise estática no nível do módulo identifica imports e caminhos de código que nunca executam e os remove. Requer informação de tipo no nível do módulo e compreensão clara dos efeitos colaterais. Redução adicional típica: variável, mas pode ser enorme em bibliotecas que entregam muitos recursos. Nível 4: inlining e dobramento de constantes. Expressões simples como 2 * 60 * 60 são avaliadas em tempo de build para 7200; funções minúsculas chamadas uma vez podem ser embutidas em seu chamador. Nível 5: mangling de propriedades. A otimização mais agressiva, os nomes de propriedades de objeto também são reescritos. Quebra qualquer código que use chaves de string (obj['name'] vs obj.name) ou que exponha nomes de propriedades como parte de seu contrato público. Quase sempre opt-in e quase sempre limitado a identificadores específicos via uma regex --mangle-props.

Uma breve história das ferramentas de minificação JavaScript

JSMin (2003). Douglas Crockford, sim, o mesmo Crockford que promoveu o JSON, escreveu o JSMin em C em 2003. Era um programinha de arquivo único que fazia remoção básica de espaços e comentários sem AST, sem análise de escopo, e com uma abordagem deliberadamente conservadora para os casos limite de ASI (Automatic Semicolon Insertion). Estabeleceu a fasquia de "a coisa mais simples que funciona" e é o ancestral espiritual de todo minificador JS baseado em regex desde então. YUI Compressor (2007). Julien Lecomte do Yahoo anunciou o YUI Compressor em 11 de agosto de 2007. Usava o tokenizador Rhino para fazer renomeação segura de símbolos, a primeira ferramenta Java amplamente usada a fazer verdadeiro mangling baseado em AST para JavaScript. Closure Compiler (2009). O Google o usava internamente desde 2005; eles o abriram sob Apache 2.0 em 5 de novembro de 2009. Closure era o otimizador mais agressivo da era, ciente de tipos via anotações JSDoc, com um modo "advanced" que podia reescrever nomes de propriedades com base em inferência de tipos. O custo era que você tinha de escrever seu código de forma compatível com Closure; falhas do modo avançado eram notórias.

UglifyJS (~2010-2012). O UglifyJS de Mihai Bazon foi o primeiro minificador JavaScript-nativo, escrito em JS, rodando em Node.js, e tornou-se o padrão npm por uma década. UglifyJS 2 acrescentou suporte a source maps e recursos ES5; UglifyJS 3 seguiu com polimento ES5 contínuo, mas nunca obteve totalmente suporte ES6+. Terser (agosto de 2018). Fabricio Matté bifurcou o UglifyJS em Terser especificamente para acrescentar suporte ES6+ sem perturbar a API estável de longa data do UglifyJS. Terser é agora o minificador JS padrão no webpack 5, Rollup, Parcel 1 e nas versões mais antigas do Next.js. swc (2017/2019). O swc de Donny "kdy1" Choi ("Speedy Web Compiler") é um compilador JavaScript/TypeScript baseado em Rust com um minificador embutido 20-70x mais rápido que o Terser. O Next.js trocou seu minificador padrão de Terser para swc a partir da versão 12 em outubro de 2021. esbuild (inverno 2019-2020). Evan Wallace, cofundador da Figma, lançou o esbuild durante as férias de inverno de 2019-2020. Escrito em Go, é 10-100x mais rápido que os bundlers baseados em JavaScript da época e traz seu próprio minificador. esbuild é agora o minificador subjacente no Vite, no tsup e em muitos templates de framework. A direção geral nos últimos cinco anos tem sido: parser escrito numa linguagem de sistemas rápida (Rust ou Go), otimizações baseadas em AST, tree shaking inteligente ciente de módulos ES. O minificador regex colado no navegador, como esta ferramenta, fica no fundo dessa escada, fazendo o trabalho mais simples que ainda é útil.

Source maps para JavaScript minificado

Um source map é um arquivo JSON acompanhante que mapeia posições na saída minificada para posições na fonte original. A especificação Source Map V3 foi escrita por John Lenz (Google) e Nick Fitzgerald (Mozilla) em 2011, e foi adotada pelo TC39 como ECMA-426 em junho de 2024, o mesmo formato de source map aplica-se tanto a JavaScript quanto a CSS. Os navegadores consomem o mapa via um comentário no final do arquivo minificado: //# sourceMappingURL=app.js.map. Quando o DevTools está aberto e o mapa é buscado, o painel Sources mostra a fonte original, com breakpoints, erros de console e stack traces todos referindo-se a ela. Os minificadores de produção (Terser, swc, esbuild, Closure) todos emitem source maps sob demanda. Esta ferramenta não, para uma ferramenta one-shot no navegador que devolve texto em vez de um par de arquivos baixáveis, source maps acrescentam complexidade significativa para benefício marginal. A divulgação honesta é que esta ferramenta é uma passagem unidirecional; minificadores de pipeline de build têm um argumento muito mais forte para source maps porque as fontes originais estão em disco e o desenvolvedor precisa depurar em tempo de execução.

Padrões dos bundlers modernos, a maioria já tem um minificador

Se você usa um pipeline de build moderno, seu minificador já está rodando. webpack 5 usa terser-webpack-plugin com Terser por padrão. Vite usa esbuild para minificação por padrão; Lightning CSS para CSS. Parcel usa swc. Next.js mudou de Terser para swc na v12 (outubro de 2021), e de Babel para swc para todo o pipeline de build na mesma versão. Remix, Astro, SvelteKit, Nuxt, Rollup, esbuild standalone, todos integram minificação em builds de produção sem intervenção do desenvolvedor. O resultado é que para quem usa um pipeline de build moderno, a minificação de JS acontece automaticamente com otimizações muito além do que uma ferramenta regex de arquivo único pode fazer. Os casos onde este minificador no navegador conquista seu lugar: páginas HTML feitas à mão com blocos <script> inline; temas WordPress entregues sem cadeia de ferramentas Node; geradores de sites estáticos que não integram minificação; snippets pontuais colados num CMS ou template de e-mail; experimentos rápidos onde montar um pipeline de build demoraria mais que o próprio script.

Escopo honesto: o que esta ferramenta faz e não faz

Esta ferramenta é um minificador baseado em regex, aproximadamente 30 linhas de JavaScript. Tokeniza string literals, template literals e regex literals em placeholders para que transformações subsequentes não corrompam seu conteúdo; remove comentários // ... e /* ... */; colapsa sequências de espaço em branco; remove espaços em torno de pontuação que não precisa deles; e restaura os literais tokenizados. A saída típica é 20-40% menor que a entrada em bytes brutos. O que esta ferramenta não faz, e que os minificadores de produção (Terser, swc, esbuild, Closure) tratam: ela não renomeia variáveis locais para letras únicas (sem mangling ciente de escopo); não realiza eliminação de código morto nem tree-shaking; não realiza dobramento de constantes nem simplificação de expressão; não emite source maps; não entende a sintaxe TypeScript (cole apenas JavaScript puro); não faz tree-shake de imports de módulos ES; não reescreve nomes de propriedades. O enquadramento honesto: cole o JavaScript que saiu do seu editor ou da sua mão, receba de volta uma versão despojada que é tipicamente 20-40% menor em bytes brutos, e use-a como artefato de deploy rápido. Para projetos com pipeline de build, use Terser, swc ou esbuild nesse pipeline; as otimizações cientes de AST são a diferença entre a redução de 20-40% desta ferramenta e os 60-80% de um minificador de produção.

As armadilhas do minificador regex

Uma passagem baseada em regex que não entende a gramática JavaScript pode corromper o código de formas sutis. As armadilhas clássicas: template literals usam crases e podem conter expressões interpoladas (`Hello ${name}!`) que parecem candidatas à remoção de comentários se a regex não for cuidadosa. Regex literals como /^\/\*/g contêm barras, sequências parecidas com comentários e conteúdo parecido com string; tratá-los mal transforma uma regex em código sintaticamente quebrado. Strings contendo texto parecido com comentário (const url = "// example.com"), remoção ingênua de comentários removeria tudo após o //. Armadilhas de ASI, Automatic Semicolon Insertion é o recurso JS que permite omitir ponto e vírgula na maior parte do tempo, mas interage mal com a remoção de espaços quando o próximo token começa com parêntese, colchete ou operador ((/regex/), [arr], +1), um colapso de espaços imprudente pode transformar "duas declarações" em "uma declaração com erro de parsing". A mitigação nesta ferramenta é a passagem de tokenização de literais que roda primeiro, substituindo cada string e regex por um placeholder único, fazendo o trabalho de comentário+espaços no código limpo, depois restaurando os placeholders. Não é perfeito, mas cobre os casos comuns. Se suspeitar que o minificador quebrou seu código, a primeira coisa a verificar é um regex literal que contenha uma sequência de barra que o tokenizador perdeu.

Privacidade: por que somente navegador importa aqui

Minificadores JS do lado servidor (ferramentas online que enviam seu código por POST a um servidor, passam-no pelo Terser lá e devolvem o resultado) exigem o envio da sua fonte. Para código de biblioteca comum isso é inofensivo. Para ferramentas internas, código de produto não lançado, JavaScript contendo chaves API inline ou credenciais de serviços terceiros, ou qualquer código que revele algoritmos proprietários ou lógica de negócio, não é. Um minificador puramente baseado no navegador, JavaScript rodando na sua aba que nunca faz uma requisição de rede após o carregamento inicial da página, contorna a questão. Você pode verificar abrindo a aba Rede do DevTools, colando o código, clicando em Minificar e observando qualquer requisição saindo. Melhor ainda, desconecte-se da internet (ou ative o modo avião) depois que a página carregar e a ferramenta ainda funcionará, o que é a prova empírica mais sólida de que nada está sendo enviado.

Perguntas frequentes

Quanto menor ficará meu código?

Para código formatado à mão com comentários e indentação, espere uma redução de tamanho de 20-40% em bytes brutos. Minificadores de produção (Terser, swc, esbuild) com otimizações AST completas alcançam 60-80%, a lacuna é renomeação de símbolos, eliminação de código morto e dobramento de constantes, nenhum dos quais uma ferramenta apenas regex pode fazer com segurança. Após compressão Brotli na borda do CDN, a economia adicional da minificação é mais modesta (5-15% além do Brotli no original não minificado) mas não é zero, e em escala soma-se.

A saída minificada quebrará meu código?

Para a vasta maioria do código, não. Os casos limite conhecidos são em torno de regex literals com sequências de barra (/foo\/bar/), template literals com interpolações embutidas atravessando linhas, e contextos de Automatic Semicolon Insertion onde retirar uma quebra de linha muda o parsing. A passagem de tokenização de literais da ferramenta trata dos casos comuns, mas se seu código for incomumente carregado em qualquer um desses padrões, teste a saída minificada num navegador antes de implantar. Para um pipeline de build de produção, use Terser ou swc, eles têm consciência AST completa e tratam esses casos corretamente.

Esta ferramenta renomeia variáveis?

Não. O mangling de variáveis, transformar function calculateTotal(itemList) em function a(b), requer análise completa de escopo sobre uma AST para saber quais nomes são seguros para renomear. Uma passagem por regex não pode fazer isso com segurança. Para renomeação de símbolos, use Terser, UglifyJS ou swc em um pipeline de build; eles implementam mangling ciente de escopo corretamente. A redução de tamanho adicional de 10-25% que produz é real e vale a pena fazer para código de produção.

Posso colar TypeScript?

Não, esta ferramenta é um minificador apenas de JavaScript. TypeScript acrescenta anotações de tipo (function add(a: number, b: number): number), interfaces, enums, decoradores e outra sintaxe que não é JavaScript válido. Compile primeiro seu TypeScript para JavaScript usando tsc, swc, esbuild ou Babel, depois cole a saída JavaScript aqui. A maioria dos projetos TypeScript já passa por um desses compiladores como parte do build, então o JavaScript existe em algum lugar.

Devo usar isto se já tenho um pipeline de build?

Provavelmente não, seu bundler está fazendo isso por você, com otimizações baseadas em AST muito além do que uma ferramenta regex pode oferecer. webpack 5 traz terser-webpack-plugin com Terser; Vite usa esbuild para JS por padrão; Parcel usa swc; Next.js usa swc desde v12 (outubro de 2021). Esta ferramenta é para os casos que seu pipeline de build não cobre: páginas HTML feitas à mão, temas WordPress entregues sem cadeia de ferramentas Node, geradores de sites estáticos que não integram minificação, snippets pontuais ou experimentos rápidos onde montar um build demoraria mais que o próprio script.

Meus arquivos são enviados?

Não. O minificador é JavaScript rodando no seu navegador. O código que você cola nunca cruza a rede, verifique na aba Rede do DevTools enquanto clica em Minificar, ou tire a página do ar depois que ela carregar e confirme que a ferramenta ainda funciona. Ferramentas internas, código de produto não lançado, scripts contendo chaves API inline ou lógica de negócio proprietária permanecem no seu dispositivo.

Ferramentas relacionadas