Exibindo PDFs em Aplicações Vue 3
Incorporar um PDF dentro de uma SPA Vue 3 parece simples—até você encontrar seu primeiro erro de CORS, descobrir que o navegador renderiza de forma diferente no Safari, ou perceber que seu documento de 200 páginas está bloqueando a thread principal. Este artigo cobre as três abordagens práticas que desenvolvedores realmente usam para exibir PDFs no Vue 3, com trade-offs honestos para cada uma.
Principais Conclusões
- As três principais abordagens para exibir PDFs no Vue 3 são embeds nativos do navegador (
<iframe>/<embed>), integração direta com PDF.js e componentes wrapper específicos do Vue. - Embeds nativos não custam nada em tamanho de bundle, mas não oferecem controle sobre estilização, barras de ferramentas ou consistência entre navegadores.
- PDF.js oferece controle total de renderização, mas adiciona um payload notável no lado do cliente—carregue-o de forma lazy com
import()dinâmico para manter os tempos de carregamento inicial rápidos. - Wrappers Vue para PDF como
vue-pdf-embedreduzem significativamente o boilerplate ao custo de alguma flexibilidade de customização. - Configuração correta do worker e lazy loading são os dois passos que previnem os problemas mais comuns relacionados a PDF em aplicações Vue.
As Três Abordagens Principais
1. Embed Nativo do Navegador: <iframe> ou <embed>
A forma mais rápida de colocar um PDF na tela é delegá-lo ao renderizador de PDF integrado do navegador.
<template>
<iframe
:src="pdfUrl"
width="100%"
height="700px"
style="border: none"
/>
</template>
<script setup lang="ts">
const pdfUrl = '/documents/report.pdf'
</script>
Quando funciona bem: Ferramentas internas, dashboards administrativos, ou qualquer contexto onde a consistência da UI não seja crítica e o PDF seja servido da mesma origem.
As limitações reais:
- Zero controle sobre a barra de ferramentas, controles de zoom ou temas
- O comportamento varia entre navegadores—Chrome, Firefox e Safari renderizam de forma diferente
- Navegadores móveis frequentemente baixam o arquivo ao invés de exibi-lo inline
- O estado de carregamento é invisível para seu componente Vue, então você não pode mostrar um spinner ou tratar erros graciosamente
Se você estiver carregando um PDF de um domínio diferente, o navegador bloqueará a requisição a menos que o servidor envie os headers Access-Control-Allow-Origin corretos. Um endpoint proxy de mesma origem no seu backend é a solução mais limpa.
2. PDF.js com Vue 3: Integração Direta
PDF.js é o motor de renderização de PDF open-source da Mozilla. A partir da série de releases 5.x, ele é distribuído como um pacote ESM-first. Você importa de build/pdf.mjs e carrega um worker separado (pdf.worker.mjs) para manter a renderização fora da thread principal.
npm install pdfjs-dist
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs'
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.mjs',
import.meta.url
).toString()
const canvasRef = ref<HTMLCanvasElement | null>(null)
onMounted(async () => {
const pdf = await pdfjsLib.getDocument('/documents/report.pdf').promise
const page = await pdf.getPage(1)
const viewport = page.getViewport({ scale: 1.5 })
const canvas = canvasRef.value!
const ctx = canvas.getContext('2d')!
canvas.height = viewport.height
canvas.width = viewport.width
await page.render({ canvasContext: ctx, viewport }).promise
})
</script>
<template>
<canvas ref="canvasRef" />
</template>
O que você ganha: Controle total sobre renderização, navegação de páginas, zoom e temas. PDF.js suporta anotações padrão e campos AcroForm, embora o comportamento de formulários e anotações possa depender da configuração de renderização.
O que você deve saber:
- O pacote
pdfjs-distadiciona um payload notável ao seu bundle cliente. Useimport()dinâmico para carregá-lo de forma lazy. - Formulários baseados em XFA (comuns em PDFs governamentais antigos) têm suporte limitado e podem não renderizar corretamente.
- Para documentos grandes, PDF.js pode buscar PDFs em chunks quando o servidor suporta requisições HTTP range (
Accept-Ranges: bytes), o que pode melhorar a performance percebida para arquivos grandes. - Configuração do worker é o problema de setup mais comum em projetos Vite. O padrão
new URL(..., import.meta.url)mostrado acima resolve o caminho do worker corretamente em tempo de build.
Discover how at OpenReplay.com.
3. Wrappers Vue para PDF
Vários componentes Vue 3 mantidos encapsulam o PDF.js e expõem uma API de componente mais simples. vue-pdf-embed é uma opção ativamente mantida que cuida do setup do worker, renderização de páginas e atualizações reativas de props para você.
<script setup lang="ts">
import VuePdfEmbed from 'vue-pdf-embed'
</script>
<template>
<VuePdfEmbed source="/documents/report.pdf" />
</template>
O trade-off é menos controle granular em troca de significativamente menos boilerplate. Esses wrappers são uma boa escolha quando você precisa de um visualizador Vue 3 de PDF funcionando rapidamente e não precisa customizar o pipeline de renderização.
Nota: Alguns pacotes mais antigos como
vue3-pdf-appnão são mais ativamente mantidos. Avalie o status de manutenção e compatibilidade de qualquer wrapper com bundlers modernos como Vite antes de adotá-lo.
Escolhendo a Abordagem Certa
| Abordagem | Custo de Bundle | Customização | Melhor Para |
|---|---|---|---|
<iframe> / <embed> | 0 KB | Nenhuma | Embeds rápidos, arquivos mesma origem |
| PDF.js direto | Payload client-side | Total | Visualizadores customizados, docs grandes |
| Wrapper Vue | Similar ao PDF.js | Moderada | Setup mais rápido, casos de uso padrão |
Conclusão
Para a maioria das aplicações Vue 3, a decisão é direta: use <iframe> para embeds simples de mesma origem, recorra a um wrapper Vue mantido quando precisar de um visualizador funcionando sem muito setup, e integre PDF.js diretamente quando precisar de controle total sobre renderização, navegação ou performance para documentos grandes. Qualquer que seja o caminho escolhido, configure o worker do PDF.js corretamente e carregue a biblioteca de forma lazy. Esses dois passos sozinhos prevenirão os problemas mais comuns que desenvolvedores encontram ao incorporar PDFs em aplicações Vue.
Perguntas Frequentes
O navegador bloqueia requisições de PDF cross-origin a menos que o servidor inclua o header Access-Control-Allow-Origin em sua resposta. A solução mais confiável é configurar um endpoint proxy de mesma origem no seu próprio backend que busca o PDF e o serve para sua aplicação Vue. Isso evita depender de configurações de servidores de terceiros que você pode não controlar.
O Vite lida com URLs de assets de forma diferente do Webpack. Use o padrão new URL com import.meta.url para resolver o caminho do worker em tempo de build. Por exemplo, defina workerSrc como new URL de pdfjs-dist/build/pdf.worker.mjs com import.meta.url, então chame toString. Isso garante que o Vite processe o arquivo worker corretamente durante builds de desenvolvimento e produção.
Sim. Após carregar o documento, faça um loop de 1 até pdf.numPages, chame getPage para cada número de página, crie um elemento canvas para cada uma e renderize-as sequencialmente ou em paralelo. Para documentos muito grandes, considere renderizar apenas as páginas visíveis e carregar outras ao rolar para evitar alto uso de memória e tempos de renderização inicial lentos.
Use um wrapper como vue-pdf-embed se você precisa de um visualizador padrão com setup mínimo e não requer customização profunda. Integre PDF.js diretamente quando precisar de controle total sobre renderização, navegação customizada, temas ou otimizações de performance como carregamento lazy de páginas. Wrappers adicionam uma camada fina sobre o PDF.js, então o custo de bundle é quase idêntico de qualquer forma.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.