Creas un proyecto Vue 3 con Vite, arrancas el servidor de desarrollo y miras la pestaña del navegador. Ahí está el logo de Vite por defecto donde debería estar el icono de tu marca. La solución está en la carpeta public/ de tu proyecto, y configurarlo correctamente lleva unos tres minutos una vez que conoces los detalles específicos de Vite.

Requisitos previos

Necesitas un proyecto Vue 3 ejecutándose con Vite, además de los archivos de favicon que quieras usar. Si aún no los tienes, genera un paquete completo (ICO, PNG y SVG) con Mzu favicondl y descárgalo listo para usar. Sin rarezas de webpack, sin reglas de copy-webpack-plugin — Vite trata la carpeta public como activos estáticos, sin configuración adicional.

Paso 1: Abre la carpeta public/

Todo proyecto Vue + Vite incluye un directorio public/ en la raíz del proyecto. Según la documentación de Vite sobre el directorio public, cualquier cosa que coloques aquí se copia sin cambios a la salida de compilación y se sirve en la ruta raíz.

Eso significa que public/favicon.ico es accesible como /favicon.ico, nunca como /public/favicon.ico. No entender esta distinción es la causa más común de que las aplicaciones Vue lleguen a producción con un icono de pestaña roto.

Paso 2: Coloca tus archivos de favicon

Coloca todo tu paquete de favicon directamente en public/:

public/
├── favicon.ico
├── favicon-16x16.png
├── favicon-32x32.png
├── apple-touch-icon.png
├── site.webmanifest
└── favicon.svg

Vite copia toda la carpeta a tu salida dist/ tal cual — sin imports, sin transformaciones. No hagas import de estos archivos desde ningún componente Vue; están destinados a permanecer fuera del bundle. El desglose completo de qué tamaños importan realmente hoy está en nuestra Guía de Tamaños de Favicon.

Paso 3: Añade etiquetas link en index.html

Abre index.html en la raíz del proyecto — el mismo archivo donde Vite monta tu aplicación Vue. Añade las declaraciones link rel="icon" dentro de <head>:

<head>
  <meta charset="UTF-8" />
  <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
  <link rel="icon" href="/favicon-32x32.png" type="image/png" sizes="32x32" />
  <link rel="icon" href="/favicon.ico" sizes="any" />
  <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
  <link rel="manifest" href="/site.webmanifest" />
</head>

El orden importa aquí. Los navegadores eligen la primera entrada rel="icon" que soporten, así que coloca el SVG primero para una escala nítida, los PNG como respaldo a continuación, y el ICO heredado al final. Todas las rutas comienzan con /, nunca con /public/.

Paso 4: Añade soporte para modo oscuro en SVG

Si quieres un cambio para modo oscuro, coloca la media query dentro del propio SVG en lugar de configurar la reactividad de Vue para ello:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
  <style>
    circle { fill: #1a1a1a; }
    @media (prefers-color-scheme: dark) {
      circle { fill: #fafafa; }
    }
  </style>
  <circle cx="16" cy="16" r="14" />
</svg>

Los navegadores cambian el relleno automáticamente — sin llamadas a watch(), sin hooks de ciclo de vida necesarios en la pestaña. Para un análisis más profundo de los patrones, consulta nuestra Guía de Modo Oscuro para Favicon.

Paso 5: Verifica en desarrollo y producción

Ejecuta npm run dev y confirma tres cosas:

  1. DevTools → Red → filtrar "favicon" muestra que cada archivo devuelve 200 OK.
  2. La pestaña del navegador muestra tu icono, no la marca de Vite por defecto.
  3. curl http://localhost:5173/favicon.svg devuelve los bytes del SVG.

Luego ejecuta npm run build e inspecciona dist/. Cada archivo de public/ debería aparecer en la raíz de dist/, sin cambios. Si falta algo en producción, es probable que las reglas de reescritura de tu hosting estén eliminando la ruta — revisa vercel.json o _redirects.

Errores comunes

Conclusión

El flujo de trabajo de la carpeta public en Vue + Vite es uno de los sistemas de favicon más limpios en el desarrollo web moderno. Coloca tus archivos, configura las etiquetas link en index.html, y Vite copia todo a dist/ exactamente donde lo pusiste. Sin configuración de plugins, sin rarezas de inyección en el head, sin Vue Router interceptando tus solicitudes — solo activos estáticos servidos desde la ruta raíz.

Genera un paquete completo de favicon con Mzu favicondl, pega las etiquetas link en tu index.html, y tu aplicación Vue se verá pulida en cada pestaña del navegador.