Vue Vapor Mode: o que é e o que muda no Vue 3.6

O Vue 3.6 ainda não saiu como versão estável. Em 6 de outubro de 2026, a versão mais recente é a 3.6.0-rc.10 (30 de setembro), e a estável continua sendo a 3.5.43 (17 de setembro). Confirmei isso no npm e nas releases do repositório vuejs/core nesta data.
O Vue Vapor Mode é a principal novidade dessa versão: um modo de compilação que dispensa o Virtual DOM e gera código que atualiza o DOM diretamente. Ele é opt-in, então você escolhe componente a componente onde usar, sem reescrever o app. Neste artigo você vê como o Vapor funciona, como ativar no Vue e no Nuxt 4.6, o que ainda não é suportado e quando vale a pena testar.
Como o Vapor funciona
No modo tradicional, quando um estado reativo muda, o Vue executa a função de renderização, monta uma nova árvore de VNodes (objetos JavaScript que descrevem a interface), compara com a árvore anterior e só então altera o DOM real.
No Vapor Mode, o compilador analisa o template e gera código que manipula o DOM diretamente. Os componentes Vapor não criam VNodes nem comparam árvores em tempo de execução. Quando uma variável reativa muda, só o trecho do DOM ligado a ela é atualizado.
Segundo as notas oficiais do Vue 3.6, o objetivo é reduzir o tamanho base do bundle e melhorar a performance. As mesmas notas dizem que o Vapor mostrou, em benchmarks de terceiros (o js-framework-benchmark), o mesmo nível de performance do Solid e do Svelte 5. Como em qualquer benchmark, o resultado depende do cenário medido.
E o Alien Signals?
O Vue 3.6 também traz uma refatoração grande do @vue/reactivity, baseada na biblioteca alien-signals. Segundo as notas do rc.1, ela melhora o desempenho e o uso de memória do sistema de reatividade. É uma mudança interna: ref, reactive, computed e watch continuam com a mesma API. Como ela faz parte do Vue 3.6, o benefício não depende de você usar o Vapor.
Como ativar o Vapor Mode
O Vapor funciona com SFCs que usam <script setup> ou só template. Você marca o componente com o atributo vapor:
<script setup vapor lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">
count is {{ count }}
</button>
</template>
Fora do Nuxt, o @vitejs/plugin-vue compila SFCs Vapor (o changelog do plugin registra suporte a componentes Vapor, inclusive só com template), então use uma versão recente.
O Vue também aceita <script vapor> como atalho de <script setup vapor>. Outra opção é colocar o marcador no template, com <template vapor>, para compilar o SFC inteiro em modo Vapor.
Componentes Vapor em um app existente
Num app criado com createApp(), é preciso instalar o vaporInteropPlugin para usar componentes Vapor:
import { createApp, vaporInteropPlugin } from 'vue'
import App from './App.vue'
createApp(App).use(vaporInteropPlugin).mount('#app')
Com o plugin instalado, componentes Vapor e componentes comuns podem ficar aninhados uns dentro dos outros. As notas do Vue avisam que isso cobre props, eventos e slots no uso padrão, mas ainda não todos os casos de borda. A recomendação deles é manter regiões distintas no app, cada uma em um modo, e evitar o aninhamento misto sempre que der.
App 100% Vapor
Se todos os componentes forem Vapor, use createVaporApp():
import { createVaporApp } from 'vue'
import App from './App.vue'
createVaporApp(App).mount('#app')
Assim o runtime do Virtual DOM não entra no bundle. Cada componente continua precisando do marcador vapor. Componentes escritos com render function ou JSX seguem sendo componentes de Virtual DOM e exigem interop. Um app Vapor também pode instalar o vaporInteropPlugin para aceitar componentes de Virtual DOM, mas isso traz o runtime de volta e reduz o ganho de tamanho.
Vapor no Nuxt 4.6
O Nuxt 4.6, lançado em 5 de outubro de 2026, suporta o Vapor em modo de interoperabilidade. A raiz do app continua no Virtual DOM, e você escolhe quais componentes ou páginas usam Vapor. Para habilitar, ligue a opção no nuxt.config.ts:
export default defineNuxtConfig({
vue: {
vapor: true,
},
})
Depois marque os componentes com <script setup vapor>, como no exemplo acima. O Nuxt exige Vue ^3.6.0-rc.2 ou mais novo. Segundo o anúncio, rotas, useAsyncData, layouts e a maioria dos componentes embutidos funcionam sem mudanças. O anúncio recomenda testar o Vapor primeiro em um projeto novo.
A documentação do Nuxt lista algumas limitações do modo de interop:
- a raiz do app não pode ser Vapor, porque os apps 100% Vapor não estão disponíveis no Nuxt;
- componentes Vapor não expõem
$elnas template refs; <ClientOnly>pula o repasse de atributos, e<NuxtIsland>, os componentes de servidor e os componentes de head que leem texto filho (<Title>,<Style>e<Noscript>) emitem aviso se receberem um slot Vapor;onPrehydratecom chave volta para a forma sem chave (e avisa em desenvolvimento), porque não há instância de componente para anexar a chave;asyncDataefetchKeyviadefineNuxtComponentnão funcionam (useuseAsyncDatano<script setup>);- composables do Nuxt chamados depois de um
awaitpodem perder o contexto.
O mesmo anúncio traz números de performance do Nuxt 4.6: o nuxt build de um projeto inicial passou de 4,4 s para 3,6 s (18% mais rápido) e a página com 300 <NuxtLink> foi de 110 para 140 req/s no SSR (+26%). O Nuxt atribui esses ganhos às otimizações gerais da versão, não ao Vapor.
Se você ainda usa Nuxt 3, vale saber que ele chegou ao fim de vida em 31 de julho de 2026.
O que o Vapor ainda não suporta
O Vapor aceita um subconjunto das APIs do Vue. As notas oficiais listam o que não está disponível ou não se aplica nos componentes Vapor:
- Options API (
data,methods,mountede companhia). Se você precisa entender a diferença, veja o artigo sobre Composition API e Options API; app.config.globalProperties;getCurrentInstance(), que retornanull;- eventos de ciclo de vida por elemento, como
@vue:mounted; v-memo;$el,$props,$attrs,$slotse$refsnas template refs de componentes.
Bibliotecas de componentes baseadas em Virtual DOM também merecem teste. As notas falam em "arestas" ao usar uma biblioteca de componentes de Virtual DOM dentro do Vapor, sem citar nenhuma biblioteca específica. Se alguma delas depende de getCurrentInstance(), o null acima pode ser um problema, mas isso só um teste no seu projeto confirma.
As notas oficiais não listam <Suspense> nem o Vue DevTools como incompatíveis com o Vapor, mas isso não garante suporte completo. O changelog das RCs registra várias correções de integração do Vapor com o Suspense, então o suporte está em andamento. Teste os dois no seu cenário antes de decidir.
O mesmo vale para SSR. O changelog das RCs traz várias correções de hidratação em componentes Vapor, o que indica que o SSR é suportado, mas ainda em ajuste. Se o seu app renderiza no servidor, teste a hidratação com atenção.
Eventos e .delegate
Nas RCs mais antigas, o Vapor delegava eventos para o document, o que fazia um stopPropagation() em um ancestral impedir o handler do filho. Desde o rc.2, os listeners são ligados direto no elemento, como no Vue tradicional, e a delegação virou opt-in com o modificador .delegate:
<button @click.delegate="onClick" />
A opção compilerOptions.eventDelegation foi removida.
Diretivas customizadas
As diretivas customizadas também têm outra interface no Vapor. Em vez de um objeto com hooks, você escreve uma função que recebe o elemento e um getter reativo, e pode devolver uma função de limpeza:
import { watchEffect } from 'vue'
const MyDirective = (el, source) => {
watchEffect(() => {
el.textContent = source()
})
return () => console.log('cleanup')
}
A assinatura completa é (node, value?, argument?, modifiers?), e value é o getter reativo. Se quiser rever o básico, o artigo sobre diretivas no Vue cobre o modelo tradicional.
Onde o Vapor ajuda
O ganho aparece onde o app faz muito trabalho de atualização de DOM: listas e tabelas densas, componentes que mudam várias vezes por segundo e páginas em que o tamanho do JavaScript inicial pesa. Para um CRUD comum, a diferença tende a passar despercebida pelo usuário.
O Vapor também não resolve problemas que não vêm do renderizador. Renderizar 10.000 itens no DOM continua lento nos dois modos, e a saída é virtualizar a lista. Chamar funções pesadas direto no template, como {{ calcularTotal(item) }}, continua sendo má ideia nos dois modos.
Vale adotar agora?
A própria equipe do Vue diz que o conjunto de recursos do Vapor está completo no RC e recomenda, por enquanto, dois usos: aplicar o Vapor em partes de um app existente, como uma página sensível a performance, e construir apps pequenos novos inteiramente em Vapor.
Para um app em produção que já roda bem no Vue 3.5, esperar a versão estável é a escolha mais segura. Para uma página isolada onde você já mediu um gargalo, um teste no Nuxt 4.6 ou num app Vue com interop é um bom experimento. Antes de começar, confira:
- você mediu o desempenho atual (o painel Performance do navegador serve) e achou um gargalo de renderização;
- o componente usa
<script setup>ou só template; - as bibliotecas de UI que ele usa funcionam com interop no seu projeto;
- você consegue isolar o Vapor numa rota ou componente e voltar atrás sem dor.
Perguntas frequentes
O que é Vapor Mode no Vue?
É um modo de compilação opt-in para SFCs, disponível no Vue 3.6 RC. Em vez de criar e comparar uma árvore de Virtual DOM em tempo de execução, o compilador gera código que atualiza o DOM diretamente.
O Vue 3.6 já saiu como estável?
Ainda não. Até 6 de outubro de 2026, a versão mais recente é a 3.6.0-rc.10, e a estável é a 3.5.43.
O Vapor Mode substitui o Virtual DOM?
Não. Ele é opcional e convive com o Virtual DOM no mesmo app, por meio do vaporInteropPlugin.
Preciso reescrever meu app para usar o Vapor?
Não. Você pode marcar um componente por vez com vapor. Os componentes que usam Options API ficam fora, porque o Vapor só aceita <script setup> e templates.
O Vapor Mode funciona com Options API?
Não. As notas oficiais listam a Options API como não suportada.
O Vapor Mode funciona com Nuxt?
Sim, desde o Nuxt 4.6, em modo de interoperabilidade: ative vue: { vapor: true } no nuxt.config.ts e marque os componentes com <script setup vapor>. A raiz do app continua no Virtual DOM.
O Vapor Mode é mais rápido que o Virtual DOM?
Segundo as notas do Vue 3.6, o Vapor chegou ao nível de Solid e Svelte 5 em benchmarks de terceiros. Para a maioria dos apps o ganho percebido é pequeno, e o efeito real no seu projeto só aparece medindo.