Cómo convertir tu proyecto Nuxt 4 en una PWA
22/01/2025
|
10 minutos de lectura
|
Compartir artículo
Convertir una aplicación Nuxt 4 en una Progressive Web App (PWA) te permite ofrecer a tus usuarios una experiencia más rápida, instalable y funcional incluso sin conexión. En este artículo veremos, de manera estructurada y profesional, cómo integrar el módulo adecuado, qué parámetros configurar y cuáles son las mejores prácticas.
1. Módulo recomendado
En Nuxt 4 la opción oficial y mantenida es @vite-pwa/nuxt, un wrapper de vite-plugin-pwa perfectamente integrado con el ecosistema Nuxt.
Instalación
npx nuxi module add @vite-pwa/nuxt
Esto añadirá automáticamente el módulo a tu nuxt.config.ts.
2. Configuración básica
En nuxt.config.ts define la sección pwa con las claves principales:
// nuxt.config.ts
import { defineNuxtConfig } from 'nuxt/config'
export default defineNuxtConfig({
modules: ['@vite-pwa/nuxt'],
pwa: {
registerType: 'autoUpdate',
manifest: {
name: 'Mi Aplicación Nuxt 4',
short_name: 'MiApp',
description: 'Aplicación Nuxt 4 con soporte PWA',
start_url: '/',
scope: '/',
display: 'standalone',
background_color: '#ffffff',
theme_color: '#0ea5e9',
icons: [
{
src: '/pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
purpose: 'any maskable'
},
{
src: '/pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any maskable'
}
]
}
}
})
Campos clave
name/short_name→ nombre largo y corto que verá el usuario.start_urlyscope→ definen el punto de inicio y el ámbito de control del Service Worker.display: 'standalone'→ hace que la app se muestre como nativa (sin barra de navegador).theme_colorybackground_color→ afectan a la barra superior y a la pantalla de carga.icons→ imprescindible incluir variantes con propósitomaskablepara asegurar compatibilidad con diferentes launchers.
3. Estrategias de Service Worker
El plugin permite varias estrategias de cacheo mediante Workbox:
pwa: {
// ...
workbox: {
cleanupOutdatedCaches: true,
navigateFallback: '/offline.html',
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
runtimeCaching: [
{
urlPattern: /^https:\/\/api\.miapp\.com\/.*$/,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
expiration: {
maxEntries: 50,
maxAgeSeconds: 60 * 60 * 24
}
}
}
]
}
}
Estrategias recomendadas
- Precaching → para los assets generados en el build.
- NetworkFirst → para APIs y contenido dinámico (prioriza la red, con fallback a cache).
- CacheFirst → para imágenes estáticas o fuentes (prioriza velocidad).
- StaleWhileRevalidate → ideal para recursos que pueden refrescarse en segundo plano.
4. Actualización de la aplicación
La propiedad registerType controla cómo se gestionan las actualizaciones:
autoUpdate→ el Service Worker se actualiza de manera transparente.prompt→ puedes mostrar un aviso al usuario antes de aplicar la nueva versión.
Además, el módulo expone la API $pwa con señales reactivas como needRefresh u offlineReady. Ejemplo de uso en un componente:
<template>
<div v-if="$pwa?.needRefresh" class="update-toast">
Nueva versión disponible.
<button @click="$pwa.updateServiceWorker()">Actualizar</button>
</div>
</template>
5. Experiencia en iOS
Aunque iOS no soporta todas las capacidades PWA, es recomendable:
- Definir
theme_colorybackground_color. - Añadir
apple-touch-iconenapp.vueoapp.html. - Probar en dispositivos reales, ya que iOS maneja la instalación y el modo standalone de forma distinta a Android.
6. Pruebas y validación
- Ejecuta un build de producción y prueba con
nuxi preview. - Abre Chrome DevTools → Application → Service Workers para verificar el registro.
- Usa Lighthouse (Auditoría PWA) para comprobar cumplimiento y detectar mejoras.
7. Página offline
Cuando un usuario pierda conexión y navegue a una página no cacheada, verá este fallback. Este es un ejemplo de offline.html listo para colocar en la carpeta public/ de tu proyecto Nuxt 4 (o en static/, según cómo tengas estructurado).
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sin conexión</title>
<style>
body {
margin: 0;
font-family: system-ui, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
text-align: center;
background: #f9fafb;
color: #111827;
}
h1 {
font-size: 2rem;
margin-bottom: 1rem;
color: #0ea5e9;
}
p {
margin-bottom: 2rem;
color: #374151;
}
button {
background: #0ea5e9;
color: #fff;
border: none;
padding: 0.75rem 1.5rem;
font-size: 1rem;
border-radius: 0.5rem;
cursor: pointer;
}
button:hover {
background: #0284c7;
}
</style>
</head>
<body>
<h1>Estás sin conexión</h1>
<p>No pudimos cargar el contenido. Vuelve a intentarlo cuando recuperes internet.</p>
<button onclick="location.reload()">Reintentar</button>
</body>
</html>
👉 Una vez añadido:
- Si en tu
nuxt.config.tsya tienes configurado:
pwa: {
workbox: {
navigateFallback: '/offline.html'
}
}
8. Ejemplo completo
Vamos a extender la configuración con reglas de runtimeCaching específicas para APIs, imágenes y fuentes, que suelen ser los tres recursos más comunes a optimizar en una PWA.
// nuxt.config.ts
import { defineNuxtConfig } from 'nuxt/config'
export default defineNuxtConfig({
modules: ['@vite-pwa/nuxt'],
pwa: {
registerType: 'autoUpdate',
manifest: {
name: 'Mi Aplicación Nuxt 4',
short_name: 'MiApp',
description: 'Aplicación Nuxt 4 con soporte PWA',
start_url: '/',
scope: '/',
display: 'standalone',
background_color: '#ffffff',
theme_color: '#0ea5e9',
icons: [
{
src: '/pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
purpose: 'any maskable'
},
{
src: '/pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any maskable'
}
]
},
workbox: {
cleanupOutdatedCaches: true,
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
navigateFallback: '/offline.html',
runtimeCaching: [
// 1. API: Network First (prioriza datos frescos)
{
urlPattern: /^https:\/\/api\.miapp\.com\/.*$/,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
networkTimeoutSeconds: 10,
cacheableResponse: { statuses: [0, 200] },
expiration: {
maxEntries: 50,
maxAgeSeconds: 60 * 60 * 24 // 1 día
}
}
},
// 2. Imágenes: Cache First (rápidas y raramente cambian)
{
urlPattern: /\.(?:png|jpg|jpeg|svg|gif|webp|avif)$/,
handler: 'CacheFirst',
options: {
cacheName: 'image-cache',
cacheableResponse: { statuses: [0, 200] },
expiration: {
maxEntries: 100,
maxAgeSeconds: 60 * 60 * 24 * 30 // 30 días
}
}
},
// 3. Fuentes: Cache First (ideal para Google Fonts u otros CDNs)
{
urlPattern: /^https:\/\/fonts\.(?:googleapis|gstatic)\.com\/.*/i,
handler: 'CacheFirst',
options: {
cacheName: 'font-cache',
cacheableResponse: { statuses: [0, 200] },
expiration: {
maxEntries: 20,
maxAgeSeconds: 60 * 60 * 24 * 365 // 1 año
}
}
}
]
}
}
})
Estrategia de cada recurso:
- APIs → NetworkFirst: intentará siempre obtener la respuesta más reciente y usará la caché solo si no hay red.
- Imágenes → CacheFirst: entrega la imagen desde caché si existe, reduciendo tiempo de carga.
- Fuentes → CacheFirst: útil para Google Fonts, que rara vez cambian.
Con esta configuración tu PWA se vuelve mucho más ágil y confiable en entornos con mala conectividad.
Puntos importantes:
- Coloca tu
offline.htmlen la carpetapublic/(recomendado). - El
navigateFallbackhará que cualquier navegación sin conexión que no esté en caché redirija a esa página. - Puedes extender el
runtimeCachingpara imágenes, fuentes u otros endpoints externos (ej. un CDN). - Con
autoUpdateel service worker se actualizará en segundo plano sin intervención del usuario.
8. Buenas prácticas
- Usa siempre HTTPS en producción.
- Incluye iconos en varias resoluciones (192px, 512px como mínimo).
- Limita cachés con
maxEntriesymaxAgeSecondspara evitar ocupar demasiado almacenamiento. - Añade una página
/offline.htmlque proporcione feedback al usuario sin conexión. - Coloca tu
offline.htmlen la carpetapublic/(recomendado). - El
navigateFallbackhará que cualquier navegación sin conexión que no esté en caché redirija a esa página. - Puedes extender el
runtimeCachingpara imágenes, fuentes u otros endpoints externos (ej. un CDN). - Con
autoUpdateel service worker se actualizará en segundo plano sin intervención del usuario. - Documenta tu estrategia de actualización (automática o con aviso).
9. Perfecto ✅ Aquí tienes un checklist de pruebas con Lighthouse para validar tu PWA en Nuxt 4. Lo puedes usar como guía rápida después de hacer nuxi build y nuxi preview.
📝 Checklist Lighthouse para PWAs en Nuxt 4
1. Instalabilidad
- Manifest detectado → Lighthouse debe mostrar que tu
manifest.jsones válido. - Iconos adecuados → Incluye al menos 192×192 y 512×512, con
purpose: maskable. - start_url válido → Se abre correctamente la app al iniciar.
- display = standalone → La app se abre como aplicación nativa, sin la barra del navegador.
2. Funcionalidad offline
- Service Worker activo → Verifica en Chrome DevTools → Application → Service Workers.
- Página offline → Navega sin conexión a una ruta que no esté en caché y comprueba que aparece
offline.html. - Precaching correcto → Asegúrate de que los assets
_nuxt/están cacheados en la primera carga.
3. Rendimiento y recursos
- Runtime caching:
- API con estrategia NetworkFirst.
- Imágenes con CacheFirst (máx. 30 días).
- Fuentes con CacheFirst (máx. 1 año).
- Limite de caché configurado (
maxEntriesymaxAgeSeconds). - Evitar recursos obsoletos →
cleanupOutdatedCaches: truehabilitado.
4. Accesibilidad y UX
- Theme color definido → Se refleja en la barra de estado del dispositivo.
- Background color definido → Pantalla de carga consistente al abrir la app.
- Meta iOS:
apple-touch-icondisponible.mobile-web-app-capableoapple-mobile-web-app-capableconfigurado si necesitas soporte específico.
5. Actualizaciones
- registerType configurado:
autoUpdatesi quieres que todo se actualice en segundo plano.promptsi prefieres notificar al usuario antes de actualizar.
- Prueba de actualización → Haz un cambio en tu código, vuelve a hacer
buildy recarga la app: el SW debería actualizarse.
6. Auditoría completa
En Lighthouse (Chrome DevTools → Audits → PWA), revisa:
- Fast and reliable (rápida y confiable).
- Installable (instalable en dispositivos).
- PWA Optimized (usa buenas prácticas).
Consejo extra: prueba tu PWA en modo avión desde el móvil real (Android e iOS). En desktop puede engañar un poco porque el navegador sigue teniendo cachés de desarrollo.
Conclusión
Convertir tu proyecto Nuxt 4 en una PWA con @vite-pwa/nuxt es un proceso directo y altamente configurable. Definir un manifest claro, implementar estrategias de cache adecuadas y cuidar la experiencia de actualización garantizará que tu aplicación no solo sea instalable, sino que además ofrezca un rendimiento superior y una experiencia de usuario consistente.