Hermes é um motor JavaScript com compilação AOT (Ahead-of-Time), desenvolvido pela Meta para React Native e otimizado para dispositivos móveis com memória limitada. De acordo com o blog oficial da Meta Engineering (2022), o Hermes reduz o tempo de inicialização do aplicativo em 20-50% e diminui o tamanho do bundle em 30-40% em comparação com o JavaScriptCore. Ao contrário do V8 ou JSC, o Hermes não usa compilação JIT no dispositivo — todo o JavaScript é compilado em bytecode durante a fase de build através do Hermes CLI. Isso é especialmente importante para iOS, onde a compilação JIT é restrita pelas políticas da App Store.
Principais pontos
Hermes é um motor JavaScript compacto de código aberto (licença MIT) criado pela Meta para React Native e otimizado para funcionar em dispositivos móveis com recursos limitados. A principal inovação do Hermes é abandonar a compilação JIT em favor do AOT (Ahead-of-Time). Durante a fase de build do aplicativo React Native, o Metro Bundler passa o JavaScript compilado para o Hermes CLI, que o transforma em bytecode HBC (Hermes ByteCode). Este bytecode é executado diretamente pelo motor sem compilação adicional no dispositivo. Essa abordagem fornece desempenho previsível: sem aquecimento JIT, sem pausas de compilação, sem consumo extra de bateria. O Hermes é projetado considerando as limitações dos dispositivos móveis: pouca RAM (1-4 GB), consumo de energia limitado e a necessidade de inicialização a frio rápida. O primeiro lançamento público do Hermes foi em 2019 e, a partir do React Native 0.70 (2022), o motor se tornou o padrão no Android.
JavaScriptCore (JSC) é o motor WebKit padrão usado pelo Safari e React Native antes da versão 0.70. O JSC suporta compilação JIT, o que fornece alto desempenho para operações JavaScript complexas. No entanto, o JIT requer aquecimento: os primeiros segundos de execução são mais lentos (modo interpretado), então o JIT compila os caminhos mais usados. No iOS, o JIT está praticamente indisponível devido às políticas da App Store (proibição de geração dinâmica de código), então o JSC no iOS funciona apenas em modo interpretado — o desempenho cai. O JSC tem um tamanho binário maior (cerca de 10 MB) e consome mais RAM devido à infraestrutura JIT. O Hermes não depende de JIT, fornecendo desempenho previsível imediatamente após a inicialização (cold start). O JSC suporta o padrão ECMAScript de forma mais completa (incluindo Proxy, BigInt, Reflect), mas ao custo de maior consumo de recursos. Para projetos React Native onde a inicialização a frio e o tamanho pequeno são críticos — o Hermes é preferível. Para projetos com cálculos JS pesados (jogos, WebGL) — o JSC pode oferecer maior desempenho de pico.
| Parâmetro | Hermes | JavaScriptCore |
|---|---|---|
| Compilação | AOT (no build) | JIT + Interpretado (no dispositivo) |
| Cold start | 20-50% mais rápido | Nível base |
| Tamanho do bundle | 30-40% menor | Nível base |
| Consumo de RAM | 20-30% menos | Nível base |
| ECMAScript | ES2020 (limitações) | ES2022+ (completo) |
| JIT no iOS | Não requerido | Indisponível (apenas interpretado) |
| Binário | ~3 MB | ~10 MB |
A compilação AOT (Ahead-of-Time) no Hermes ocorre em duas etapas. Na primeira etapa, o Metro Bundler coleta os arquivos JavaScript em um único bundle e os passa para o Hermes CLI (o utilitário hermesc). Na segunda etapa, o hermesc analisa o AST do JavaScript, gera uma representação intermediária HIR (Hermes Intermediate Representation) e então emite bytecode HBC binário. O resultado é um arquivo .hbc que contém apenas bytecode sem o JavaScript original. O runtime do Hermes carrega o HBC diretamente, sem análise e compilação. Isso acelera radicalmente a inicialização: em vez de analisar milhares de linhas de JS (async), o motor lê um formato binário pré-compilado. O AOT também reduz o tamanho: o bytecode é em média 30% mais compacto que o AST do JavaScript. A desvantagem do AOT — a incapacidade de executar eval, new Function ou require dinâmico em tempo de execução — todos os módulos devem ser conhecidos no momento do build.
# Install Hermes CLI standalone
npm install hermes-engine
# Compile JS to HBC bytecode
npx hermesc -emit-binary -out bundle.hbc bundle.js
# Bytecode statistics
npx hermesc -dump-bytecode bundle.hbc # shows HBC instructions
# Original JS vs HBC size
wc -c bundle.js # 2,300,000 bytes
wc -c bundle.hbc # 1,450,000 bytes (37% reduction)
O desempenho do Hermes é medido por três métricas principais: Time-To-Interactive (TTI), tamanho do APK/IPA e consumo de RAM. De acordo com dados da Meta, no Android o Hermes reduz o TTI em 34% em comparação com o JSC: de 4,2 segundos para 2,8 segundos em um dispositivo de médio porte (Moto G7). O tamanho do APK diminui 28% graças ao bytecode compacto e à ausência de bibliotecas JIT. O consumo de RAM é em média 22% menor sob a mesma carga — isso é especialmente importante para dispositivos com 2-3 GB de RAM. No iOS, o ganho é ainda mais significativo: como o JSC não pode usar JIT, o Hermes fornece uma melhoria de TTI de até 45%. As métricas são baseadas em testes da Meta com o aplicativo Facebook Lite. Em projetos reais, o ganho varia: para telas simples (listas, texto) o Hermes dá uma melhoria maior, para animações pesadas — menor. Ferramenta de perfilamento: React Native Profiler + hermes profile --heap.
Hermes inclui um perfilador de memória integrado acessível através do Chrome DevTools. Conecte-se ao aplicativo via Metro, abra a guia Memória e selecione Hermes (JavaScript) nos tipos de snapshot. O Hermes suporta três tipos de snapshot: Heap Snapshot (todos os objetos), Allocation Timeline (tempo de vida dos objetos) e Allocation Sampling (perfil de amostragem). O Hades GC reduz as pausas do GC ao mínimo — em média uma pausa de 2-5ms a cada 10 segundos de operação, contra pausas de 10-20ms para o JSC no mesmo período.
Hades GC é o coletor de lixo do Hermes, projetado para cenários móveis com pausas mínimas. Ao contrário do GC mark-sweep do JSC, o Hades usa coleta concorrente: o coletor trabalha em paralelo com a thread principal de execução, parando-a apenas por intervalos curtos. O Hades GC divide o heap em gerações: a geração jovem (nursery) é coletada com frequência e rapidez (Scavenge), a geração velha é coletada com menos frequência e com pausas menores. O tamanho do heap é configurável: por padrão — 2/3 da RAM disponível do aplicativo, limite mínimo — 32 MB. O Hades não usa a abordagem stop-the-world: mesmo uma coleta completa da geração velha não leva mais de 5-8ms. O coletor é otimizado para cenários móveis típicos: muitos objetos de curta duração (strings temporárias, objetos React fiber), poucos de longa duração. Para aplicações com criação intensiva de objetos (listas, animações), o Hades fornece FPS mais suaves em comparação com o JSC.
A habilitação do Hermes depende da versão do React Native e da plataforma. A partir do React Native 0.70, o Hermes está habilitado por padrão para Android em novos projetos. Para iOS, o Hermes é opcional. Para habilitar no Android: no arquivo android/app/build.gradle defina enableHermes: true no bloco project.ext.react.enableHermes. Para iOS: defina hermes_enabled como true no Podfile através de use_react_native!(:path => config[:reactNativePath], :hermes_enabled => true). Após habilitar, execute pod install. Para projetos existentes, verifique a compatibilidade das bibliotecas: o Hermes não suporta Proxy, eval e alguns recursos do ES2021. Use npx react-native info para verificar a configuração. Para alternar entre Hermes e JSC, altere a flag e execute uma limpeza e reconstrução.
// android/app/build.gradle — enable Hermes
project.ext.react = [
enableHermes: true,
cliPath: "node_modules/react-native/cli.js"
]
// iOS/Podfile — enable Hermes on iOS
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
target 'MyApp' do
config = use_native_modules!
use_react_native!(
:path => config[:reactNativePath],
:hermes_enabled => true
)
end
As principais limitações do Hermes estão relacionadas à falta de JIT. O Hermes não suporta: Proxy e Reflect API (usados no MobX, Vue, alguns gerenciadores de estado), BigInt (números grandes), Symbol.toStringTag, WeakRef e FinalizationRegistry. As funções eval e new Function geram uma exceção em tempo de execução. Os callbacks dos métodos Array.prototype.flat e flatMap com um argumento this funcionam com limitações. Formatos de data ISO 8601 com fusos horários não são processados completamente. A maioria dessas limitações não afeta aplicativos React Native típicos: React e React Native usam um conjunto limitado de recursos ES. Se uma biblioteca exigir Proxy (por exemplo, MobX 6+ com Proxy), use configure({ useProxies: false }) ou escolha uma alternativa. Para verificar a compatibilidade do código existente, execute npx hermesc -check no seu bundle — ele mostrará a lista de recursos não suportados.
Perguntas frequentes
No console do aplicativo, execute console.log(global.HermesInternal). Se o objeto HermesInternal existir — o aplicativo está rodando no Hermes. Alternativamente: console.log(global.HermesInternal?.getRuntimeProperties()) — exibirá a versão do motor e os parâmetros do GC. Em builds Release, o HermesInternal pode não estar disponível para minimizar o tamanho.
Verifique as configurações do Podfile: o Hermes no iOS requer New Architecture (Fabric Renderer). Defina :hermes_enabled => true, execute pod install --repo-update. Se o projeto estiver atualizando do React Native abaixo de 0.70, verifique a compatibilidade das bibliotecas com a New Architecture. Desabilite o Hermes se uma biblioteca de terceiros exigir JSC — altere a flag para false e reinstale os Pods.
Não, o Hermes não afeta o Hot Reload / Fast Refresh. Durante o desenvolvimento, o Metro executa o bundle JavaScript sem compilação Hermes (JS puro). O bytecode Hermes é compilado apenas para builds Release. No modo Debug, o JavaScriptCore padrão ou o Hermes em modo interpretado é usado. A velocidade do Hot Reload não muda quando o Hermes está habilitado na configuração — a alternância ocorre apenas na etapa de build de produção.
Sim, a partir do Expo SDK 45, o Hermes é suportado para managed workflow. No app.json especifique "jsEngine": "hermes". Para bare workflow, o Hermes funciona como em um projeto React Native normal. O Expo Go não suporta Hermes — use Expo Dev Client ou EAS Build para builds com Hermes. Verifique a compatibilidade das bibliotecas através do expo doctor.
Use o React Native Performance Monitor (métricas FPS) e as Hermes Profiling Tools. Crie duas versões do aplicativo — com Hermes e JSC — no mesmo dispositivo. Meça: cold start (do toque no ícone até a primeira tela interativa), TTI (Time-To-Interactive), tamanho do APK/IPA e consumo máximo de RAM. Execute os testes pelo menos 3 vezes para cada configuração. Vantagem típica do Hermes: inicialização 20-40% mais rápida, RAM 15-25% menor.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também