[{"data":1,"prerenderedAt":2826},["ShallowReactive",2],{"/es/articles/5-amazing-raycast-nuxt-snippets":3},{"id":4,"title":5,"body":6,"date":2810,"description":2811,"extension":2812,"head":2813,"image":2814,"meta":2815,"navigation":145,"ogImage":2813,"path":2816,"readingTime":1938,"robots":2813,"schemaOrg":2813,"seo":2817,"sitemap":2818,"stem":2819,"tags":2820,"__hash__":2825},"articles_es/es/articles/5-amazing-raycast-nuxt-snippets.md","Cómo convertir tu proyecto Nuxt 4 en una PWA",{"type":7,"value":8,"toc":2779},"minimark",[9,18,21,26,51,56,87,94,96,100,110,416,420,479,481,488,495,704,708,737,739,743,750,764,779,889,891,895,898,928,930,934,960,962,966,983,1557,1560,1568,1602,1604,1608,1619,2320,2324,2344,2347,2351,2383,2385,2389,2437,2439,2452,2454,2458,2462,2513,2515,2519,2557,2559,2563,2620,2622,2626,2671,2673,2677,2712,2714,2718,2721,2751,2756,2758,2762,2776],[10,11,12,13,17],"p",{},"Convertir una aplicación Nuxt 4 en una ",[14,15,16],"strong",{},"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.",[19,20],"hr",{},[22,23,25],"h2",{"id":24},"_1-módulo-recomendado","1. Módulo recomendado",[10,27,28,29,41,42,46,47,50],{},"En Nuxt 4 la opción oficial y mantenida es ",[14,30,31],{},[32,33,37],"a",{"href":34,"rel":35},"https://vite-pwa-org.netlify.app/frameworks/nuxt/",[36],"nofollow",[38,39,40],"code",{},"@vite-pwa/nuxt",", un ",[43,44,45],"em",{},"wrapper"," de ",[38,48,49],{},"vite-plugin-pwa"," perfectamente integrado con el ecosistema Nuxt.",[52,53,55],"h3",{"id":54},"instalación","Instalación",[57,58,63],"pre",{"className":59,"code":60,"language":61,"meta":62,"style":62},"language-bash shiki shiki-themes github-light github-dark github-dark","npx nuxi module add @vite-pwa/nuxt\n","bash","",[38,64,65],{"__ignoreMap":62},[66,67,70,74,78,81,84],"span",{"class":68,"line":69},"line",1,[66,71,73],{"class":72},"shcOC","npx",[66,75,77],{"class":76},"sfrk1"," nuxi",[66,79,80],{"class":76}," module",[66,82,83],{"class":76}," add",[66,85,86],{"class":76}," @vite-pwa/nuxt\n",[10,88,89,90,93],{},"Esto añadirá automáticamente el módulo a tu ",[38,91,92],{},"nuxt.config.ts",".",[19,95],{},[22,97,99],{"id":98},"_2-configuración-básica","2. Configuración básica",[10,101,102,103,105,106,109],{},"En ",[38,104,92],{}," define la sección ",[38,107,108],{},"pwa"," con las claves principales:",[57,111,115],{"className":112,"code":113,"language":114,"meta":62,"style":62},"language-ts shiki shiki-themes github-light github-dark github-dark","// nuxt.config.ts\nimport { defineNuxtConfig } from 'nuxt/config'\n\nexport default defineNuxtConfig({\n  modules: ['@vite-pwa/nuxt'],\n  pwa: {\n    registerType: 'autoUpdate',\n    manifest: {\n      name: 'Mi Aplicación Nuxt 4',\n      short_name: 'MiApp',\n      description: 'Aplicación Nuxt 4 con soporte PWA',\n      start_url: '/',\n      scope: '/',\n      display: 'standalone',\n      background_color: '#ffffff',\n      theme_color: '#0ea5e9',\n      icons: [\n        {\n          src: '/pwa-192x192.png',\n          sizes: '192x192',\n          type: 'image/png',\n          purpose: 'any maskable'\n        },\n        {\n          src: '/pwa-512x512.png',\n          sizes: '512x512',\n          type: 'image/png',\n          purpose: 'any maskable'\n        }\n      ]\n    }\n  }\n})\n","ts",[38,116,117,123,140,147,162,174,180,192,198,209,220,231,242,252,263,274,285,291,297,308,319,330,339,345,350,360,370,379,386,392,398,404,410],{"__ignoreMap":62},[66,118,119],{"class":68,"line":69},[66,120,122],{"class":121},"sCsY4","// nuxt.config.ts\n",[66,124,126,130,134,137],{"class":68,"line":125},2,[66,127,129],{"class":128},"so5gQ","import",[66,131,133],{"class":132},"slsVL"," { defineNuxtConfig } ",[66,135,136],{"class":128},"from",[66,138,139],{"class":76}," 'nuxt/config'\n",[66,141,143],{"class":68,"line":142},3,[66,144,146],{"emptyLinePlaceholder":145},true,"\n",[66,148,150,153,156,159],{"class":68,"line":149},4,[66,151,152],{"class":128},"export",[66,154,155],{"class":128}," default",[66,157,158],{"class":72}," defineNuxtConfig",[66,160,161],{"class":132},"({\n",[66,163,165,168,171],{"class":68,"line":164},5,[66,166,167],{"class":132},"  modules: [",[66,169,170],{"class":76},"'@vite-pwa/nuxt'",[66,172,173],{"class":132},"],\n",[66,175,177],{"class":68,"line":176},6,[66,178,179],{"class":132},"  pwa: {\n",[66,181,183,186,189],{"class":68,"line":182},7,[66,184,185],{"class":132},"    registerType: ",[66,187,188],{"class":76},"'autoUpdate'",[66,190,191],{"class":132},",\n",[66,193,195],{"class":68,"line":194},8,[66,196,197],{"class":132},"    manifest: {\n",[66,199,201,204,207],{"class":68,"line":200},9,[66,202,203],{"class":132},"      name: ",[66,205,206],{"class":76},"'Mi Aplicación Nuxt 4'",[66,208,191],{"class":132},[66,210,212,215,218],{"class":68,"line":211},10,[66,213,214],{"class":132},"      short_name: ",[66,216,217],{"class":76},"'MiApp'",[66,219,191],{"class":132},[66,221,223,226,229],{"class":68,"line":222},11,[66,224,225],{"class":132},"      description: ",[66,227,228],{"class":76},"'Aplicación Nuxt 4 con soporte PWA'",[66,230,191],{"class":132},[66,232,234,237,240],{"class":68,"line":233},12,[66,235,236],{"class":132},"      start_url: ",[66,238,239],{"class":76},"'/'",[66,241,191],{"class":132},[66,243,245,248,250],{"class":68,"line":244},13,[66,246,247],{"class":132},"      scope: ",[66,249,239],{"class":76},[66,251,191],{"class":132},[66,253,255,258,261],{"class":68,"line":254},14,[66,256,257],{"class":132},"      display: ",[66,259,260],{"class":76},"'standalone'",[66,262,191],{"class":132},[66,264,266,269,272],{"class":68,"line":265},15,[66,267,268],{"class":132},"      background_color: ",[66,270,271],{"class":76},"'#ffffff'",[66,273,191],{"class":132},[66,275,277,280,283],{"class":68,"line":276},16,[66,278,279],{"class":132},"      theme_color: ",[66,281,282],{"class":76},"'#0ea5e9'",[66,284,191],{"class":132},[66,286,288],{"class":68,"line":287},17,[66,289,290],{"class":132},"      icons: [\n",[66,292,294],{"class":68,"line":293},18,[66,295,296],{"class":132},"        {\n",[66,298,300,303,306],{"class":68,"line":299},19,[66,301,302],{"class":132},"          src: ",[66,304,305],{"class":76},"'/pwa-192x192.png'",[66,307,191],{"class":132},[66,309,311,314,317],{"class":68,"line":310},20,[66,312,313],{"class":132},"          sizes: ",[66,315,316],{"class":76},"'192x192'",[66,318,191],{"class":132},[66,320,322,325,328],{"class":68,"line":321},21,[66,323,324],{"class":132},"          type: ",[66,326,327],{"class":76},"'image/png'",[66,329,191],{"class":132},[66,331,333,336],{"class":68,"line":332},22,[66,334,335],{"class":132},"          purpose: ",[66,337,338],{"class":76},"'any maskable'\n",[66,340,342],{"class":68,"line":341},23,[66,343,344],{"class":132},"        },\n",[66,346,348],{"class":68,"line":347},24,[66,349,296],{"class":132},[66,351,353,355,358],{"class":68,"line":352},25,[66,354,302],{"class":132},[66,356,357],{"class":76},"'/pwa-512x512.png'",[66,359,191],{"class":132},[66,361,363,365,368],{"class":68,"line":362},26,[66,364,313],{"class":132},[66,366,367],{"class":76},"'512x512'",[66,369,191],{"class":132},[66,371,373,375,377],{"class":68,"line":372},27,[66,374,324],{"class":132},[66,376,327],{"class":76},[66,378,191],{"class":132},[66,380,382,384],{"class":68,"line":381},28,[66,383,335],{"class":132},[66,385,338],{"class":76},[66,387,389],{"class":68,"line":388},29,[66,390,391],{"class":132},"        }\n",[66,393,395],{"class":68,"line":394},30,[66,396,397],{"class":132},"      ]\n",[66,399,401],{"class":68,"line":400},31,[66,402,403],{"class":132},"    }\n",[66,405,407],{"class":68,"line":406},32,[66,408,409],{"class":132},"  }\n",[66,411,413],{"class":68,"line":412},33,[66,414,415],{"class":132},"})\n",[52,417,419],{"id":418},"campos-clave","Campos clave",[421,422,423,436,448,456,467],"ul",{},[424,425,426,435],"li",{},[14,427,428,431,432],{},[38,429,430],{},"name"," / ",[38,433,434],{},"short_name"," → nombre largo y corto que verá el usuario.",[424,437,438,447],{},[14,439,440,443,444],{},[38,441,442],{},"start_url"," y ",[38,445,446],{},"scope"," → definen el punto de inicio y el ámbito de control del Service Worker.",[424,449,450,455],{},[14,451,452],{},[38,453,454],{},"display: 'standalone'"," → hace que la app se muestre como nativa (sin barra de navegador).",[424,457,458,466],{},[14,459,460,443,463],{},[38,461,462],{},"theme_color",[38,464,465],{},"background_color"," → afectan a la barra superior y a la pantalla de carga.",[424,468,469,474,475,478],{},[14,470,471],{},[38,472,473],{},"icons"," → imprescindible incluir variantes con propósito ",[38,476,477],{},"maskable"," para asegurar compatibilidad con diferentes launchers.",[19,480],{},[22,482,484,485],{"id":483},"_3-estrategias-de-service-worker","3. Estrategias de ",[43,486,487],{},"Service Worker",[10,489,490,491,494],{},"El plugin permite varias estrategias de cacheo mediante ",[14,492,493],{},"Workbox",":",[57,496,498],{"className":112,"code":497,"language":114,"meta":62,"style":62},"pwa: {\n  // ...\n  workbox: {\n    cleanupOutdatedCaches: true,\n    navigateFallback: '/offline.html',\n    globPatterns: ['**/*.{js,css,html,ico,png,svg}'],\n    runtimeCaching: [\n      {\n        urlPattern: /^https:\\/\\/api\\.miapp\\.com\\/.*$/,\n        handler: 'NetworkFirst',\n        options: {\n          cacheName: 'api-cache',\n          expiration: {\n            maxEntries: 50,\n            maxAgeSeconds: 60 * 60 * 24\n          }\n        }\n      }\n    ]\n  }\n}\n",[38,499,500,507,512,519,533,545,558,566,571,617,627,632,642,647,657,676,681,685,690,695,699],{"__ignoreMap":62},[66,501,502,504],{"class":68,"line":69},[66,503,108],{"class":72},[66,505,506],{"class":132},": {\n",[66,508,509],{"class":68,"line":125},[66,510,511],{"class":121},"  // ...\n",[66,513,514,517],{"class":68,"line":142},[66,515,516],{"class":72},"  workbox",[66,518,506],{"class":132},[66,520,521,524,527,531],{"class":68,"line":149},[66,522,523],{"class":72},"    cleanupOutdatedCaches",[66,525,526],{"class":132},": ",[66,528,530],{"class":529},"suiK_","true",[66,532,191],{"class":132},[66,534,535,538,540,543],{"class":68,"line":164},[66,536,537],{"class":72},"    navigateFallback",[66,539,526],{"class":132},[66,541,542],{"class":76},"'/offline.html'",[66,544,191],{"class":132},[66,546,547,550,553,556],{"class":68,"line":176},[66,548,549],{"class":72},"    globPatterns",[66,551,552],{"class":132},": [",[66,554,555],{"class":76},"'**/*.{js,css,html,ico,png,svg}'",[66,557,173],{"class":132},[66,559,560,563],{"class":68,"line":182},[66,561,562],{"class":72},"    runtimeCaching",[66,564,565],{"class":132},": [\n",[66,567,568],{"class":68,"line":194},[66,569,570],{"class":132},"      {\n",[66,572,573,576,579,582,586,590,593,596,599,601,604,607,609,612,615],{"class":68,"line":200},[66,574,575],{"class":132},"        urlPattern:",[66,577,578],{"class":76}," /",[66,580,581],{"class":128},"^",[66,583,585],{"class":584},"sQeJH","https:",[66,587,589],{"class":588},"sAxt1","\\/\\/",[66,591,592],{"class":584},"api",[66,594,595],{"class":588},"\\.",[66,597,598],{"class":584},"miapp",[66,600,595],{"class":588},[66,602,603],{"class":584},"com",[66,605,606],{"class":588},"\\/",[66,608,93],{"class":529},[66,610,611],{"class":128},"*$",[66,613,614],{"class":76},"/",[66,616,191],{"class":132},[66,618,619,622,625],{"class":68,"line":211},[66,620,621],{"class":132},"        handler: ",[66,623,624],{"class":76},"'NetworkFirst'",[66,626,191],{"class":132},[66,628,629],{"class":68,"line":222},[66,630,631],{"class":132},"        options: {\n",[66,633,634,637,640],{"class":68,"line":233},[66,635,636],{"class":132},"          cacheName: ",[66,638,639],{"class":76},"'api-cache'",[66,641,191],{"class":132},[66,643,644],{"class":68,"line":244},[66,645,646],{"class":132},"          expiration: {\n",[66,648,649,652,655],{"class":68,"line":254},[66,650,651],{"class":132},"            maxEntries: ",[66,653,654],{"class":529},"50",[66,656,191],{"class":132},[66,658,659,662,665,668,671,673],{"class":68,"line":265},[66,660,661],{"class":132},"            maxAgeSeconds: ",[66,663,664],{"class":529},"60",[66,666,667],{"class":128}," *",[66,669,670],{"class":529}," 60",[66,672,667],{"class":128},[66,674,675],{"class":529}," 24\n",[66,677,678],{"class":68,"line":276},[66,679,680],{"class":132},"          }\n",[66,682,683],{"class":68,"line":287},[66,684,391],{"class":132},[66,686,687],{"class":68,"line":293},[66,688,689],{"class":132},"      }\n",[66,691,692],{"class":68,"line":299},[66,693,694],{"class":132},"    ]\n",[66,696,697],{"class":68,"line":310},[66,698,409],{"class":132},[66,700,701],{"class":68,"line":321},[66,702,703],{"class":132},"}\n",[52,705,707],{"id":706},"estrategias-recomendadas","Estrategias recomendadas",[421,709,710,719,725,731],{},[424,711,712,715,716,93],{},[14,713,714],{},"Precaching"," → para los assets generados en el ",[43,717,718],{},"build",[424,720,721,724],{},[14,722,723],{},"NetworkFirst"," → para APIs y contenido dinámico (prioriza la red, con fallback a cache).",[424,726,727,730],{},[14,728,729],{},"CacheFirst"," → para imágenes estáticas o fuentes (prioriza velocidad).",[424,732,733,736],{},[14,734,735],{},"StaleWhileRevalidate"," → ideal para recursos que pueden refrescarse en segundo plano.",[19,738],{},[22,740,742],{"id":741},"_4-actualización-de-la-aplicación","4. Actualización de la aplicación",[10,744,745,746,749],{},"La propiedad ",[38,747,748],{},"registerType"," controla cómo se gestionan las actualizaciones:",[421,751,752,758],{},[424,753,754,757],{},[38,755,756],{},"autoUpdate"," → el Service Worker se actualiza de manera transparente.",[424,759,760,763],{},[38,761,762],{},"prompt"," → puedes mostrar un aviso al usuario antes de aplicar la nueva versión.",[10,765,766,767,770,771,774,775,778],{},"Además, el módulo expone la API ",[38,768,769],{},"$pwa"," con señales reactivas como ",[38,772,773],{},"needRefresh"," u ",[38,776,777],{},"offlineReady",". Ejemplo de uso en un componente:",[57,780,784],{"className":781,"code":782,"language":783,"meta":62,"style":62},"language-vue shiki shiki-themes github-light github-dark github-dark","\u003Ctemplate>\n  \u003Cdiv v-if=\"$pwa?.needRefresh\" class=\"update-toast\">\n    Nueva versión disponible.\n    \u003Cbutton @click=\"$pwa.updateServiceWorker()\">Actualizar\u003C/button>\n  \u003C/div>\n\u003C/template>\n","vue",[38,785,786,798,830,835,871,880],{"__ignoreMap":62},[66,787,788,791,795],{"class":68,"line":69},[66,789,790],{"class":132},"\u003C",[66,792,794],{"class":793},"sByVh","template",[66,796,797],{"class":132},">\n",[66,799,800,803,806,809,812,815,818,820,823,825,828],{"class":68,"line":125},[66,801,802],{"class":132},"  \u003C",[66,804,805],{"class":793},"div",[66,807,808],{"class":128}," v-if",[66,810,811],{"class":132},"=",[66,813,814],{"class":76},"\"",[66,816,817],{"class":132},"$pwa?.needRefresh",[66,819,814],{"class":76},[66,821,822],{"class":72}," class",[66,824,811],{"class":132},[66,826,827],{"class":76},"\"update-toast\"",[66,829,797],{"class":132},[66,831,832],{"class":68,"line":142},[66,833,834],{"class":132},"    Nueva versión disponible.\n",[66,836,837,840,843,846,849,851,853,856,859,862,864,867,869],{"class":68,"line":149},[66,838,839],{"class":132},"    \u003C",[66,841,842],{"class":793},"button",[66,844,845],{"class":132}," @",[66,847,848],{"class":72},"click",[66,850,811],{"class":132},[66,852,814],{"class":76},[66,854,855],{"class":132},"$pwa.",[66,857,858],{"class":72},"updateServiceWorker",[66,860,861],{"class":132},"()",[66,863,814],{"class":76},[66,865,866],{"class":132},">Actualizar\u003C/",[66,868,842],{"class":793},[66,870,797],{"class":132},[66,872,873,876,878],{"class":68,"line":164},[66,874,875],{"class":132},"  \u003C/",[66,877,805],{"class":793},[66,879,797],{"class":132},[66,881,882,885,887],{"class":68,"line":176},[66,883,884],{"class":132},"\u003C/",[66,886,794],{"class":793},[66,888,797],{"class":132},[19,890],{},[22,892,894],{"id":893},"_5-experiencia-en-ios","5. Experiencia en iOS",[10,896,897],{},"Aunque iOS no soporta todas las capacidades PWA, es recomendable:",[421,899,900,907,921],{},[424,901,902,903,443,905,93],{},"Definir ",[38,904,462],{},[38,906,465],{},[424,908,909,910,913,914,917,918,93],{},"Añadir ",[38,911,912],{},"apple-touch-icon"," en ",[38,915,916],{},"app.vue"," o ",[38,919,920],{},"app.html",[424,922,923,924,927],{},"Probar en dispositivos reales, ya que iOS maneja la instalación y el modo ",[43,925,926],{},"standalone"," de forma distinta a Android.",[19,929],{},[22,931,933],{"id":932},"_6-pruebas-y-validación","6. Pruebas y validación",[935,936,937,946,953],"ol",{},[424,938,939,940,942,943,93],{},"Ejecuta un ",[43,941,718],{}," de producción y prueba con ",[38,944,945],{},"nuxi preview",[424,947,948,949,952],{},"Abre Chrome DevTools → ",[14,950,951],{},"Application → Service Workers"," para verificar el registro.",[424,954,955,956,959],{},"Usa ",[14,957,958],{},"Lighthouse"," (Auditoría PWA) para comprobar cumplimiento y detectar mejoras.",[19,961],{},[22,963,965],{"id":964},"_7-página-offline","7. Página offline",[10,967,968,969,972,973,978,979,982],{},"Cuando un usuario pierda conexión y navegue a una página no cacheada, verá este fallback. Este es un ejemplo de ",[38,970,971],{},"offline.html"," listo para colocar en la carpeta ",[14,974,975],{},[38,976,977],{},"public/"," de tu proyecto Nuxt 4 (o en ",[38,980,981],{},"static/",", según cómo tengas estructurado).",[57,984,988],{"className":985,"code":986,"language":987,"meta":62,"style":62},"language-html shiki shiki-themes github-light github-dark github-dark","\u003C!DOCTYPE html>\n\u003Chtml lang=\"es\">\n\u003Chead>\n  \u003Cmeta charset=\"UTF-8\" />\n  \u003Cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n  \u003Ctitle>Sin conexión\u003C/title>\n  \u003Cstyle>\n    body {\n      margin: 0;\n      font-family: system-ui, sans-serif;\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      justify-content: center;\n      height: 100vh;\n      text-align: center;\n      background: #f9fafb;\n      color: #111827;\n    }\n    h1 {\n      font-size: 2rem;\n      margin-bottom: 1rem;\n      color: #0ea5e9;\n    }\n    p {\n      margin-bottom: 2rem;\n      color: #374151;\n    }\n    button {\n      background: #0ea5e9;\n      color: #fff;\n      border: none;\n      padding: 0.75rem 1.5rem;\n      font-size: 1rem;\n      border-radius: 0.5rem;\n      cursor: pointer;\n    }\n    button:hover {\n      background: #0284c7;\n    }\n  \u003C/style>\n\u003C/head>\n\u003Cbody>\n  \u003Ch1>Estás sin conexión\u003C/h1>\n  \u003Cp>No pudimos cargar el contenido. Vuelve a intentarlo cuando recuperes internet.\u003C/p>\n  \u003Cbutton onclick=\"location.reload()\">Reintentar\u003C/button>\n\u003C/body>\n\u003C/html>\n","html",[38,989,990,1003,1019,1028,1046,1070,1084,1093,1101,1114,1132,1144,1156,1168,1179,1194,1205,1217,1229,1233,1240,1255,1269,1280,1284,1291,1303,1314,1318,1325,1335,1346,1358,1377,1390,1405,1418,1423,1433,1445,1450,1459,1468,1478,1493,1507,1539,1548],{"__ignoreMap":62},[66,991,992,995,998,1001],{"class":68,"line":69},[66,993,994],{"class":132},"\u003C!",[66,996,997],{"class":793},"DOCTYPE",[66,999,1000],{"class":72}," html",[66,1002,797],{"class":132},[66,1004,1005,1007,1009,1012,1014,1017],{"class":68,"line":125},[66,1006,790],{"class":132},[66,1008,987],{"class":793},[66,1010,1011],{"class":72}," lang",[66,1013,811],{"class":132},[66,1015,1016],{"class":76},"\"es\"",[66,1018,797],{"class":132},[66,1020,1021,1023,1026],{"class":68,"line":142},[66,1022,790],{"class":132},[66,1024,1025],{"class":793},"head",[66,1027,797],{"class":132},[66,1029,1030,1032,1035,1038,1040,1043],{"class":68,"line":149},[66,1031,802],{"class":132},[66,1033,1034],{"class":793},"meta",[66,1036,1037],{"class":72}," charset",[66,1039,811],{"class":132},[66,1041,1042],{"class":76},"\"UTF-8\"",[66,1044,1045],{"class":132}," />\n",[66,1047,1048,1050,1052,1055,1057,1060,1063,1065,1068],{"class":68,"line":164},[66,1049,802],{"class":132},[66,1051,1034],{"class":793},[66,1053,1054],{"class":72}," name",[66,1056,811],{"class":132},[66,1058,1059],{"class":76},"\"viewport\"",[66,1061,1062],{"class":72}," content",[66,1064,811],{"class":132},[66,1066,1067],{"class":76},"\"width=device-width, initial-scale=1.0\"",[66,1069,1045],{"class":132},[66,1071,1072,1074,1077,1080,1082],{"class":68,"line":176},[66,1073,802],{"class":132},[66,1075,1076],{"class":793},"title",[66,1078,1079],{"class":132},">Sin conexión\u003C/",[66,1081,1076],{"class":793},[66,1083,797],{"class":132},[66,1085,1086,1088,1091],{"class":68,"line":182},[66,1087,802],{"class":132},[66,1089,1090],{"class":793},"style",[66,1092,797],{"class":132},[66,1094,1095,1098],{"class":68,"line":194},[66,1096,1097],{"class":793},"    body",[66,1099,1100],{"class":132}," {\n",[66,1102,1103,1106,1108,1111],{"class":68,"line":200},[66,1104,1105],{"class":529},"      margin",[66,1107,526],{"class":132},[66,1109,1110],{"class":529},"0",[66,1112,1113],{"class":132},";\n",[66,1115,1116,1119,1121,1124,1127,1130],{"class":68,"line":211},[66,1117,1118],{"class":529},"      font-family",[66,1120,526],{"class":132},[66,1122,1123],{"class":529},"system-ui",[66,1125,1126],{"class":132},", ",[66,1128,1129],{"class":529},"sans-serif",[66,1131,1113],{"class":132},[66,1133,1134,1137,1139,1142],{"class":68,"line":222},[66,1135,1136],{"class":529},"      display",[66,1138,526],{"class":132},[66,1140,1141],{"class":529},"flex",[66,1143,1113],{"class":132},[66,1145,1146,1149,1151,1154],{"class":68,"line":233},[66,1147,1148],{"class":529},"      flex-direction",[66,1150,526],{"class":132},[66,1152,1153],{"class":529},"column",[66,1155,1113],{"class":132},[66,1157,1158,1161,1163,1166],{"class":68,"line":244},[66,1159,1160],{"class":529},"      align-items",[66,1162,526],{"class":132},[66,1164,1165],{"class":529},"center",[66,1167,1113],{"class":132},[66,1169,1170,1173,1175,1177],{"class":68,"line":254},[66,1171,1172],{"class":529},"      justify-content",[66,1174,526],{"class":132},[66,1176,1165],{"class":529},[66,1178,1113],{"class":132},[66,1180,1181,1184,1186,1189,1192],{"class":68,"line":265},[66,1182,1183],{"class":529},"      height",[66,1185,526],{"class":132},[66,1187,1188],{"class":529},"100",[66,1190,1191],{"class":128},"vh",[66,1193,1113],{"class":132},[66,1195,1196,1199,1201,1203],{"class":68,"line":276},[66,1197,1198],{"class":529},"      text-align",[66,1200,526],{"class":132},[66,1202,1165],{"class":529},[66,1204,1113],{"class":132},[66,1206,1207,1210,1212,1215],{"class":68,"line":287},[66,1208,1209],{"class":529},"      background",[66,1211,526],{"class":132},[66,1213,1214],{"class":529},"#f9fafb",[66,1216,1113],{"class":132},[66,1218,1219,1222,1224,1227],{"class":68,"line":293},[66,1220,1221],{"class":529},"      color",[66,1223,526],{"class":132},[66,1225,1226],{"class":529},"#111827",[66,1228,1113],{"class":132},[66,1230,1231],{"class":68,"line":299},[66,1232,403],{"class":132},[66,1234,1235,1238],{"class":68,"line":310},[66,1236,1237],{"class":793},"    h1",[66,1239,1100],{"class":132},[66,1241,1242,1245,1247,1250,1253],{"class":68,"line":321},[66,1243,1244],{"class":529},"      font-size",[66,1246,526],{"class":132},[66,1248,1249],{"class":529},"2",[66,1251,1252],{"class":128},"rem",[66,1254,1113],{"class":132},[66,1256,1257,1260,1262,1265,1267],{"class":68,"line":332},[66,1258,1259],{"class":529},"      margin-bottom",[66,1261,526],{"class":132},[66,1263,1264],{"class":529},"1",[66,1266,1252],{"class":128},[66,1268,1113],{"class":132},[66,1270,1271,1273,1275,1278],{"class":68,"line":341},[66,1272,1221],{"class":529},[66,1274,526],{"class":132},[66,1276,1277],{"class":529},"#0ea5e9",[66,1279,1113],{"class":132},[66,1281,1282],{"class":68,"line":347},[66,1283,403],{"class":132},[66,1285,1286,1289],{"class":68,"line":352},[66,1287,1288],{"class":793},"    p",[66,1290,1100],{"class":132},[66,1292,1293,1295,1297,1299,1301],{"class":68,"line":362},[66,1294,1259],{"class":529},[66,1296,526],{"class":132},[66,1298,1249],{"class":529},[66,1300,1252],{"class":128},[66,1302,1113],{"class":132},[66,1304,1305,1307,1309,1312],{"class":68,"line":372},[66,1306,1221],{"class":529},[66,1308,526],{"class":132},[66,1310,1311],{"class":529},"#374151",[66,1313,1113],{"class":132},[66,1315,1316],{"class":68,"line":381},[66,1317,403],{"class":132},[66,1319,1320,1323],{"class":68,"line":388},[66,1321,1322],{"class":793},"    button",[66,1324,1100],{"class":132},[66,1326,1327,1329,1331,1333],{"class":68,"line":394},[66,1328,1209],{"class":529},[66,1330,526],{"class":132},[66,1332,1277],{"class":529},[66,1334,1113],{"class":132},[66,1336,1337,1339,1341,1344],{"class":68,"line":400},[66,1338,1221],{"class":529},[66,1340,526],{"class":132},[66,1342,1343],{"class":529},"#fff",[66,1345,1113],{"class":132},[66,1347,1348,1351,1353,1356],{"class":68,"line":406},[66,1349,1350],{"class":529},"      border",[66,1352,526],{"class":132},[66,1354,1355],{"class":529},"none",[66,1357,1113],{"class":132},[66,1359,1360,1363,1365,1368,1370,1373,1375],{"class":68,"line":412},[66,1361,1362],{"class":529},"      padding",[66,1364,526],{"class":132},[66,1366,1367],{"class":529},"0.75",[66,1369,1252],{"class":128},[66,1371,1372],{"class":529}," 1.5",[66,1374,1252],{"class":128},[66,1376,1113],{"class":132},[66,1378,1380,1382,1384,1386,1388],{"class":68,"line":1379},34,[66,1381,1244],{"class":529},[66,1383,526],{"class":132},[66,1385,1264],{"class":529},[66,1387,1252],{"class":128},[66,1389,1113],{"class":132},[66,1391,1393,1396,1398,1401,1403],{"class":68,"line":1392},35,[66,1394,1395],{"class":529},"      border-radius",[66,1397,526],{"class":132},[66,1399,1400],{"class":529},"0.5",[66,1402,1252],{"class":128},[66,1404,1113],{"class":132},[66,1406,1408,1411,1413,1416],{"class":68,"line":1407},36,[66,1409,1410],{"class":529},"      cursor",[66,1412,526],{"class":132},[66,1414,1415],{"class":529},"pointer",[66,1417,1113],{"class":132},[66,1419,1421],{"class":68,"line":1420},37,[66,1422,403],{"class":132},[66,1424,1426,1428,1431],{"class":68,"line":1425},38,[66,1427,1322],{"class":793},[66,1429,1430],{"class":72},":hover",[66,1432,1100],{"class":132},[66,1434,1436,1438,1440,1443],{"class":68,"line":1435},39,[66,1437,1209],{"class":529},[66,1439,526],{"class":132},[66,1441,1442],{"class":529},"#0284c7",[66,1444,1113],{"class":132},[66,1446,1448],{"class":68,"line":1447},40,[66,1449,403],{"class":132},[66,1451,1453,1455,1457],{"class":68,"line":1452},41,[66,1454,875],{"class":132},[66,1456,1090],{"class":793},[66,1458,797],{"class":132},[66,1460,1462,1464,1466],{"class":68,"line":1461},42,[66,1463,884],{"class":132},[66,1465,1025],{"class":793},[66,1467,797],{"class":132},[66,1469,1471,1473,1476],{"class":68,"line":1470},43,[66,1472,790],{"class":132},[66,1474,1475],{"class":793},"body",[66,1477,797],{"class":132},[66,1479,1481,1483,1486,1489,1491],{"class":68,"line":1480},44,[66,1482,802],{"class":132},[66,1484,1485],{"class":793},"h1",[66,1487,1488],{"class":132},">Estás sin conexión\u003C/",[66,1490,1485],{"class":793},[66,1492,797],{"class":132},[66,1494,1496,1498,1500,1503,1505],{"class":68,"line":1495},45,[66,1497,802],{"class":132},[66,1499,10],{"class":793},[66,1501,1502],{"class":132},">No pudimos cargar el contenido. Vuelve a intentarlo cuando recuperes internet.\u003C/",[66,1504,10],{"class":793},[66,1506,797],{"class":132},[66,1508,1510,1512,1514,1517,1519,1521,1524,1526,1529,1532,1535,1537],{"class":68,"line":1509},46,[66,1511,802],{"class":132},[66,1513,842],{"class":793},[66,1515,1516],{"class":72}," onclick",[66,1518,811],{"class":132},[66,1520,814],{"class":76},[66,1522,1523],{"class":132},"location",[66,1525,93],{"class":76},[66,1527,1528],{"class":72},"reload",[66,1530,1531],{"class":76},"()\"",[66,1533,1534],{"class":132},">Reintentar\u003C/",[66,1536,842],{"class":793},[66,1538,797],{"class":132},[66,1540,1542,1544,1546],{"class":68,"line":1541},47,[66,1543,884],{"class":132},[66,1545,1475],{"class":793},[66,1547,797],{"class":132},[66,1549,1551,1553,1555],{"class":68,"line":1550},48,[66,1552,884],{"class":132},[66,1554,987],{"class":793},[66,1556,797],{"class":132},[10,1558,1559],{},"👉 Una vez añadido:",[421,1561,1562],{},[424,1563,1564,1565,1567],{},"Si en tu ",[38,1566,92],{}," ya tienes configurado:",[57,1569,1571],{"className":112,"code":1570,"language":114,"meta":62,"style":62},"pwa: {\n  workbox: {\n    navigateFallback: '/offline.html'\n  }\n}\n",[38,1572,1573,1579,1585,1594,1598],{"__ignoreMap":62},[66,1574,1575,1577],{"class":68,"line":69},[66,1576,108],{"class":72},[66,1578,506],{"class":132},[66,1580,1581,1583],{"class":68,"line":125},[66,1582,516],{"class":72},[66,1584,506],{"class":132},[66,1586,1587,1589,1591],{"class":68,"line":142},[66,1588,537],{"class":72},[66,1590,526],{"class":132},[66,1592,1593],{"class":76},"'/offline.html'\n",[66,1595,1596],{"class":68,"line":149},[66,1597,409],{"class":132},[66,1599,1600],{"class":68,"line":164},[66,1601,703],{"class":132},[19,1603],{},[22,1605,1607],{"id":1606},"_8-ejemplo-completo","8. Ejemplo completo",[10,1609,1610,1611,1614,1615,1618],{},"Vamos a extender la configuración con reglas de ",[14,1612,1613],{},"runtimeCaching"," específicas para ",[14,1616,1617],{},"APIs, imágenes y fuentes",", que suelen ser los tres recursos más comunes a optimizar en una PWA.",[57,1620,1622],{"className":112,"code":1621,"language":114,"meta":62,"style":62},"// nuxt.config.ts\nimport { defineNuxtConfig } from 'nuxt/config'\n\nexport default defineNuxtConfig({\n  modules: ['@vite-pwa/nuxt'],\n  pwa: {\n    registerType: 'autoUpdate',\n    manifest: {\n      name: 'Mi Aplicación Nuxt 4',\n      short_name: 'MiApp',\n      description: 'Aplicación Nuxt 4 con soporte PWA',\n      start_url: '/',\n      scope: '/',\n      display: 'standalone',\n      background_color: '#ffffff',\n      theme_color: '#0ea5e9',\n      icons: [\n        {\n          src: '/pwa-192x192.png',\n          sizes: '192x192',\n          type: 'image/png',\n          purpose: 'any maskable'\n        },\n        {\n          src: '/pwa-512x512.png',\n          sizes: '512x512',\n          type: 'image/png',\n          purpose: 'any maskable'\n        }\n      ]\n    },\n    workbox: {\n      cleanupOutdatedCaches: true,\n      globPatterns: ['**/*.{js,css,html,ico,png,svg}'],\n      navigateFallback: '/offline.html',\n      runtimeCaching: [\n        // 1. API: Network First (prioriza datos frescos)\n        {\n          urlPattern: /^https:\\/\\/api\\.miapp\\.com\\/.*$/,\n          handler: 'NetworkFirst',\n          options: {\n            cacheName: 'api-cache',\n            networkTimeoutSeconds: 10,\n            cacheableResponse: { statuses: [0, 200] },\n            expiration: {\n              maxEntries: 50,\n              maxAgeSeconds: 60 * 60 * 24 // 1 día\n            }\n          }\n        },\n        // 2. Imágenes: Cache First (rápidas y raramente cambian)\n        {\n          urlPattern: /\\.(?:png|jpg|jpeg|svg|gif|webp|avif)$/,\n          handler: 'CacheFirst',\n          options: {\n            cacheName: 'image-cache',\n            cacheableResponse: { statuses: [0, 200] },\n            expiration: {\n              maxEntries: 100,\n              maxAgeSeconds: 60 * 60 * 24 * 30 // 30 días\n            }\n          }\n        },\n        // 3. Fuentes: Cache First (ideal para Google Fonts u otros CDNs)\n        {\n          urlPattern: /^https:\\/\\/fonts\\.(?:googleapis|gstatic)\\.com\\/.*/i,\n          handler: 'CacheFirst',\n          options: {\n            cacheName: 'font-cache',\n            cacheableResponse: { statuses: [0, 200] },\n            expiration: {\n              maxEntries: 20,\n              maxAgeSeconds: 60 * 60 * 24 * 365 // 1 año\n            }\n          }\n        }\n      ]\n    }\n  }\n})\n",[38,1623,1624,1628,1638,1642,1652,1660,1664,1672,1676,1684,1692,1700,1708,1716,1724,1732,1740,1744,1748,1756,1764,1772,1778,1782,1786,1794,1802,1810,1816,1820,1824,1829,1834,1843,1852,1861,1866,1871,1875,1908,1917,1922,1931,1941,1956,1961,1970,1989,1994,1999,2004,2010,2015,2065,2075,2080,2090,2103,2108,2117,2140,2145,2150,2155,2161,2166,2210,2219,2224,2234,2247,2252,2262,2285,2290,2295,2300,2305,2310,2315],{"__ignoreMap":62},[66,1625,1626],{"class":68,"line":69},[66,1627,122],{"class":121},[66,1629,1630,1632,1634,1636],{"class":68,"line":125},[66,1631,129],{"class":128},[66,1633,133],{"class":132},[66,1635,136],{"class":128},[66,1637,139],{"class":76},[66,1639,1640],{"class":68,"line":142},[66,1641,146],{"emptyLinePlaceholder":145},[66,1643,1644,1646,1648,1650],{"class":68,"line":149},[66,1645,152],{"class":128},[66,1647,155],{"class":128},[66,1649,158],{"class":72},[66,1651,161],{"class":132},[66,1653,1654,1656,1658],{"class":68,"line":164},[66,1655,167],{"class":132},[66,1657,170],{"class":76},[66,1659,173],{"class":132},[66,1661,1662],{"class":68,"line":176},[66,1663,179],{"class":132},[66,1665,1666,1668,1670],{"class":68,"line":182},[66,1667,185],{"class":132},[66,1669,188],{"class":76},[66,1671,191],{"class":132},[66,1673,1674],{"class":68,"line":194},[66,1675,197],{"class":132},[66,1677,1678,1680,1682],{"class":68,"line":200},[66,1679,203],{"class":132},[66,1681,206],{"class":76},[66,1683,191],{"class":132},[66,1685,1686,1688,1690],{"class":68,"line":211},[66,1687,214],{"class":132},[66,1689,217],{"class":76},[66,1691,191],{"class":132},[66,1693,1694,1696,1698],{"class":68,"line":222},[66,1695,225],{"class":132},[66,1697,228],{"class":76},[66,1699,191],{"class":132},[66,1701,1702,1704,1706],{"class":68,"line":233},[66,1703,236],{"class":132},[66,1705,239],{"class":76},[66,1707,191],{"class":132},[66,1709,1710,1712,1714],{"class":68,"line":244},[66,1711,247],{"class":132},[66,1713,239],{"class":76},[66,1715,191],{"class":132},[66,1717,1718,1720,1722],{"class":68,"line":254},[66,1719,257],{"class":132},[66,1721,260],{"class":76},[66,1723,191],{"class":132},[66,1725,1726,1728,1730],{"class":68,"line":265},[66,1727,268],{"class":132},[66,1729,271],{"class":76},[66,1731,191],{"class":132},[66,1733,1734,1736,1738],{"class":68,"line":276},[66,1735,279],{"class":132},[66,1737,282],{"class":76},[66,1739,191],{"class":132},[66,1741,1742],{"class":68,"line":287},[66,1743,290],{"class":132},[66,1745,1746],{"class":68,"line":293},[66,1747,296],{"class":132},[66,1749,1750,1752,1754],{"class":68,"line":299},[66,1751,302],{"class":132},[66,1753,305],{"class":76},[66,1755,191],{"class":132},[66,1757,1758,1760,1762],{"class":68,"line":310},[66,1759,313],{"class":132},[66,1761,316],{"class":76},[66,1763,191],{"class":132},[66,1765,1766,1768,1770],{"class":68,"line":321},[66,1767,324],{"class":132},[66,1769,327],{"class":76},[66,1771,191],{"class":132},[66,1773,1774,1776],{"class":68,"line":332},[66,1775,335],{"class":132},[66,1777,338],{"class":76},[66,1779,1780],{"class":68,"line":341},[66,1781,344],{"class":132},[66,1783,1784],{"class":68,"line":347},[66,1785,296],{"class":132},[66,1787,1788,1790,1792],{"class":68,"line":352},[66,1789,302],{"class":132},[66,1791,357],{"class":76},[66,1793,191],{"class":132},[66,1795,1796,1798,1800],{"class":68,"line":362},[66,1797,313],{"class":132},[66,1799,367],{"class":76},[66,1801,191],{"class":132},[66,1803,1804,1806,1808],{"class":68,"line":372},[66,1805,324],{"class":132},[66,1807,327],{"class":76},[66,1809,191],{"class":132},[66,1811,1812,1814],{"class":68,"line":381},[66,1813,335],{"class":132},[66,1815,338],{"class":76},[66,1817,1818],{"class":68,"line":388},[66,1819,391],{"class":132},[66,1821,1822],{"class":68,"line":394},[66,1823,397],{"class":132},[66,1825,1826],{"class":68,"line":400},[66,1827,1828],{"class":132},"    },\n",[66,1830,1831],{"class":68,"line":406},[66,1832,1833],{"class":132},"    workbox: {\n",[66,1835,1836,1839,1841],{"class":68,"line":412},[66,1837,1838],{"class":132},"      cleanupOutdatedCaches: ",[66,1840,530],{"class":529},[66,1842,191],{"class":132},[66,1844,1845,1848,1850],{"class":68,"line":1379},[66,1846,1847],{"class":132},"      globPatterns: [",[66,1849,555],{"class":76},[66,1851,173],{"class":132},[66,1853,1854,1857,1859],{"class":68,"line":1392},[66,1855,1856],{"class":132},"      navigateFallback: ",[66,1858,542],{"class":76},[66,1860,191],{"class":132},[66,1862,1863],{"class":68,"line":1407},[66,1864,1865],{"class":132},"      runtimeCaching: [\n",[66,1867,1868],{"class":68,"line":1420},[66,1869,1870],{"class":121},"        // 1. API: Network First (prioriza datos frescos)\n",[66,1872,1873],{"class":68,"line":1425},[66,1874,296],{"class":132},[66,1876,1877,1880,1882,1884,1886,1888,1890,1892,1894,1896,1898,1900,1902,1904,1906],{"class":68,"line":1435},[66,1878,1879],{"class":132},"          urlPattern:",[66,1881,578],{"class":76},[66,1883,581],{"class":128},[66,1885,585],{"class":584},[66,1887,589],{"class":588},[66,1889,592],{"class":584},[66,1891,595],{"class":588},[66,1893,598],{"class":584},[66,1895,595],{"class":588},[66,1897,603],{"class":584},[66,1899,606],{"class":588},[66,1901,93],{"class":529},[66,1903,611],{"class":128},[66,1905,614],{"class":76},[66,1907,191],{"class":132},[66,1909,1910,1913,1915],{"class":68,"line":1447},[66,1911,1912],{"class":132},"          handler: ",[66,1914,624],{"class":76},[66,1916,191],{"class":132},[66,1918,1919],{"class":68,"line":1452},[66,1920,1921],{"class":132},"          options: {\n",[66,1923,1924,1927,1929],{"class":68,"line":1461},[66,1925,1926],{"class":132},"            cacheName: ",[66,1928,639],{"class":76},[66,1930,191],{"class":132},[66,1932,1933,1936,1939],{"class":68,"line":1470},[66,1934,1935],{"class":132},"            networkTimeoutSeconds: ",[66,1937,1938],{"class":529},"10",[66,1940,191],{"class":132},[66,1942,1943,1946,1948,1950,1953],{"class":68,"line":1480},[66,1944,1945],{"class":132},"            cacheableResponse: { statuses: [",[66,1947,1110],{"class":529},[66,1949,1126],{"class":132},[66,1951,1952],{"class":529},"200",[66,1954,1955],{"class":132},"] },\n",[66,1957,1958],{"class":68,"line":1495},[66,1959,1960],{"class":132},"            expiration: {\n",[66,1962,1963,1966,1968],{"class":68,"line":1509},[66,1964,1965],{"class":132},"              maxEntries: ",[66,1967,654],{"class":529},[66,1969,191],{"class":132},[66,1971,1972,1975,1977,1979,1981,1983,1986],{"class":68,"line":1541},[66,1973,1974],{"class":132},"              maxAgeSeconds: ",[66,1976,664],{"class":529},[66,1978,667],{"class":128},[66,1980,670],{"class":529},[66,1982,667],{"class":128},[66,1984,1985],{"class":529}," 24",[66,1987,1988],{"class":121}," // 1 día\n",[66,1990,1991],{"class":68,"line":1550},[66,1992,1993],{"class":132},"            }\n",[66,1995,1997],{"class":68,"line":1996},49,[66,1998,680],{"class":132},[66,2000,2002],{"class":68,"line":2001},50,[66,2003,344],{"class":132},[66,2005,2007],{"class":68,"line":2006},51,[66,2008,2009],{"class":121},"        // 2. Imágenes: Cache First (rápidas y raramente cambian)\n",[66,2011,2013],{"class":68,"line":2012},52,[66,2014,296],{"class":132},[66,2016,2018,2020,2022,2024,2027,2030,2033,2035,2038,2040,2043,2045,2048,2050,2053,2055,2058,2061,2063],{"class":68,"line":2017},53,[66,2019,1879],{"class":132},[66,2021,578],{"class":76},[66,2023,595],{"class":588},[66,2025,2026],{"class":584},"(?:png",[66,2028,2029],{"class":128},"|",[66,2031,2032],{"class":584},"jpg",[66,2034,2029],{"class":128},[66,2036,2037],{"class":584},"jpeg",[66,2039,2029],{"class":128},[66,2041,2042],{"class":584},"svg",[66,2044,2029],{"class":128},[66,2046,2047],{"class":584},"gif",[66,2049,2029],{"class":128},[66,2051,2052],{"class":584},"webp",[66,2054,2029],{"class":128},[66,2056,2057],{"class":584},"avif)",[66,2059,2060],{"class":128},"$",[66,2062,614],{"class":76},[66,2064,191],{"class":132},[66,2066,2068,2070,2073],{"class":68,"line":2067},54,[66,2069,1912],{"class":132},[66,2071,2072],{"class":76},"'CacheFirst'",[66,2074,191],{"class":132},[66,2076,2078],{"class":68,"line":2077},55,[66,2079,1921],{"class":132},[66,2081,2083,2085,2088],{"class":68,"line":2082},56,[66,2084,1926],{"class":132},[66,2086,2087],{"class":76},"'image-cache'",[66,2089,191],{"class":132},[66,2091,2093,2095,2097,2099,2101],{"class":68,"line":2092},57,[66,2094,1945],{"class":132},[66,2096,1110],{"class":529},[66,2098,1126],{"class":132},[66,2100,1952],{"class":529},[66,2102,1955],{"class":132},[66,2104,2106],{"class":68,"line":2105},58,[66,2107,1960],{"class":132},[66,2109,2111,2113,2115],{"class":68,"line":2110},59,[66,2112,1965],{"class":132},[66,2114,1188],{"class":529},[66,2116,191],{"class":132},[66,2118,2120,2122,2124,2126,2128,2130,2132,2134,2137],{"class":68,"line":2119},60,[66,2121,1974],{"class":132},[66,2123,664],{"class":529},[66,2125,667],{"class":128},[66,2127,670],{"class":529},[66,2129,667],{"class":128},[66,2131,1985],{"class":529},[66,2133,667],{"class":128},[66,2135,2136],{"class":529}," 30",[66,2138,2139],{"class":121}," // 30 días\n",[66,2141,2143],{"class":68,"line":2142},61,[66,2144,1993],{"class":132},[66,2146,2148],{"class":68,"line":2147},62,[66,2149,680],{"class":132},[66,2151,2153],{"class":68,"line":2152},63,[66,2154,344],{"class":132},[66,2156,2158],{"class":68,"line":2157},64,[66,2159,2160],{"class":121},"        // 3. Fuentes: Cache First (ideal para Google Fonts u otros CDNs)\n",[66,2162,2164],{"class":68,"line":2163},65,[66,2165,296],{"class":132},[66,2167,2169,2171,2173,2175,2177,2179,2182,2184,2187,2189,2192,2194,2196,2198,2200,2203,2205,2208],{"class":68,"line":2168},66,[66,2170,1879],{"class":132},[66,2172,578],{"class":76},[66,2174,581],{"class":128},[66,2176,585],{"class":584},[66,2178,589],{"class":588},[66,2180,2181],{"class":584},"fonts",[66,2183,595],{"class":588},[66,2185,2186],{"class":584},"(?:googleapis",[66,2188,2029],{"class":128},[66,2190,2191],{"class":584},"gstatic)",[66,2193,595],{"class":588},[66,2195,603],{"class":584},[66,2197,606],{"class":588},[66,2199,93],{"class":529},[66,2201,2202],{"class":128},"*",[66,2204,614],{"class":76},[66,2206,2207],{"class":128},"i",[66,2209,191],{"class":132},[66,2211,2213,2215,2217],{"class":68,"line":2212},67,[66,2214,1912],{"class":132},[66,2216,2072],{"class":76},[66,2218,191],{"class":132},[66,2220,2222],{"class":68,"line":2221},68,[66,2223,1921],{"class":132},[66,2225,2227,2229,2232],{"class":68,"line":2226},69,[66,2228,1926],{"class":132},[66,2230,2231],{"class":76},"'font-cache'",[66,2233,191],{"class":132},[66,2235,2237,2239,2241,2243,2245],{"class":68,"line":2236},70,[66,2238,1945],{"class":132},[66,2240,1110],{"class":529},[66,2242,1126],{"class":132},[66,2244,1952],{"class":529},[66,2246,1955],{"class":132},[66,2248,2250],{"class":68,"line":2249},71,[66,2251,1960],{"class":132},[66,2253,2255,2257,2260],{"class":68,"line":2254},72,[66,2256,1965],{"class":132},[66,2258,2259],{"class":529},"20",[66,2261,191],{"class":132},[66,2263,2265,2267,2269,2271,2273,2275,2277,2279,2282],{"class":68,"line":2264},73,[66,2266,1974],{"class":132},[66,2268,664],{"class":529},[66,2270,667],{"class":128},[66,2272,670],{"class":529},[66,2274,667],{"class":128},[66,2276,1985],{"class":529},[66,2278,667],{"class":128},[66,2280,2281],{"class":529}," 365",[66,2283,2284],{"class":121}," // 1 año\n",[66,2286,2288],{"class":68,"line":2287},74,[66,2289,1993],{"class":132},[66,2291,2293],{"class":68,"line":2292},75,[66,2294,680],{"class":132},[66,2296,2298],{"class":68,"line":2297},76,[66,2299,391],{"class":132},[66,2301,2303],{"class":68,"line":2302},77,[66,2304,397],{"class":132},[66,2306,2308],{"class":68,"line":2307},78,[66,2309,403],{"class":132},[66,2311,2313],{"class":68,"line":2312},79,[66,2314,409],{"class":132},[66,2316,2318],{"class":68,"line":2317},80,[66,2319,415],{"class":132},[52,2321,2323],{"id":2322},"estrategia-de-cada-recurso","Estrategia de cada recurso:",[421,2325,2326,2332,2338],{},[424,2327,2328,2331],{},[14,2329,2330],{},"APIs → NetworkFirst",": intentará siempre obtener la respuesta más reciente y usará la caché solo si no hay red.",[424,2333,2334,2337],{},[14,2335,2336],{},"Imágenes → CacheFirst",": entrega la imagen desde caché si existe, reduciendo tiempo de carga.",[424,2339,2340,2343],{},[14,2341,2342],{},"Fuentes → CacheFirst",": útil para Google Fonts, que rara vez cambian.",[10,2345,2346],{},"Con esta configuración tu PWA se vuelve mucho más ágil y confiable en entornos con mala conectividad.",[52,2348,2350],{"id":2349},"puntos-importantes","Puntos importantes:",[421,2352,2353,2364,2371,2377],{},[424,2354,2355,2356,2360,2361,2363],{},"Coloca tu ",[14,2357,2358],{},[38,2359,971],{}," en la carpeta ",[38,2362,977],{}," (recomendado).",[424,2365,2366,2367,2370],{},"El ",[38,2368,2369],{},"navigateFallback"," hará que cualquier navegación sin conexión que no esté en caché redirija a esa página.",[424,2372,2373,2374,2376],{},"Puedes extender el ",[38,2375,1613],{}," para imágenes, fuentes u otros endpoints externos (ej. un CDN).",[424,2378,2379,2380,2382],{},"Con ",[38,2381,756],{}," el service worker se actualizará en segundo plano sin intervención del usuario.",[19,2384],{},[22,2386,2388],{"id":2387},"_8-buenas-prácticas","8. Buenas prácticas",[421,2390,2391,2394,2397,2407,2414,2422,2426,2430,2434],{},[424,2392,2393],{},"Usa siempre HTTPS en producción.",[424,2395,2396],{},"Incluye iconos en varias resoluciones (192px, 512px como mínimo).",[424,2398,2399,2400,443,2403,2406],{},"Limita cachés con ",[38,2401,2402],{},"maxEntries",[38,2404,2405],{},"maxAgeSeconds"," para evitar ocupar demasiado almacenamiento.",[424,2408,2409,2410,2413],{},"Añade una página ",[38,2411,2412],{},"/offline.html"," que proporcione feedback al usuario sin conexión.",[424,2415,2355,2416,2360,2420,2363],{},[14,2417,2418],{},[38,2419,971],{},[38,2421,977],{},[424,2423,2366,2424,2370],{},[38,2425,2369],{},[424,2427,2373,2428,2376],{},[38,2429,1613],{},[424,2431,2379,2432,2382],{},[38,2433,756],{},[424,2435,2436],{},"Documenta tu estrategia de actualización (automática o con aviso).",[19,2438],{},[22,2440,2442,2443,2446,2447,443,2450,93],{"id":2441},"_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","9. Perfecto ✅ Aquí tienes un ",[14,2444,2445],{},"checklist de pruebas con Lighthouse"," para validar tu PWA en Nuxt 4. Lo puedes usar como guía rápida después de hacer ",[38,2448,2449],{},"nuxi build",[38,2451,945],{},[19,2453],{},[1485,2455,2457],{"id":2456},"checklist-lighthouse-para-pwas-en-nuxt-4","📝 Checklist Lighthouse para PWAs en Nuxt 4",[52,2459,2461],{"id":2460},"_1-instalabilidad","1. Instalabilidad",[421,2463,2466,2483,2495,2504],{"className":2464},[2465],"contains-task-list",[424,2467,2470,2474,2475,2478,2479,2482],{"className":2468},[2469],"task-list-item",[2471,2472],"input",{"disabled":145,"type":2473},"checkbox"," ",[14,2476,2477],{},"Manifest detectado"," → Lighthouse debe mostrar que tu ",[38,2480,2481],{},"manifest.json"," es válido.",[424,2484,2486,2474,2488,2491,2492,93],{"className":2485},[2469],[2471,2487],{"disabled":145,"type":2473},[14,2489,2490],{},"Iconos adecuados"," → Incluye al menos 192×192 y 512×512, con ",[38,2493,2494],{},"purpose: maskable",[424,2496,2498,2474,2500,2503],{"className":2497},[2469],[2471,2499],{"disabled":145,"type":2473},[14,2501,2502],{},"start_url válido"," → Se abre correctamente la app al iniciar.",[424,2505,2507,2474,2509,2512],{"className":2506},[2469],[2471,2508],{"disabled":145,"type":2473},[14,2510,2511],{},"display = standalone"," → La app se abre como aplicación nativa, sin la barra del navegador.",[19,2514],{},[52,2516,2518],{"id":2517},"_2-funcionalidad-offline","2. Funcionalidad offline",[421,2520,2522,2533,2544],{"className":2521},[2465],[424,2523,2525,2474,2527,2530,2531,93],{"className":2524},[2469],[2471,2526],{"disabled":145,"type":2473},[14,2528,2529],{},"Service Worker activo"," → Verifica en Chrome DevTools → ",[43,2532,951],{},[424,2534,2536,2474,2538,2541,2542,93],{"className":2535},[2469],[2471,2537],{"disabled":145,"type":2473},[14,2539,2540],{},"Página offline"," → Navega sin conexión a una ruta que no esté en caché y comprueba que aparece ",[38,2543,971],{},[424,2545,2547,2474,2549,2552,2553,2556],{"className":2546},[2469],[2471,2548],{"disabled":145,"type":2473},[14,2550,2551],{},"Precaching correcto"," → Asegúrate de que los assets ",[38,2554,2555],{},"_nuxt/"," están cacheados en la primera carga.",[19,2558],{},[52,2560,2562],{"id":2561},"_3-rendimiento-y-recursos","3. Rendimiento y recursos",[421,2564,2566,2593,2607],{"className":2565},[2465],[424,2567,2569,2474,2571,494,2574],{"className":2568},[2469],[2471,2570],{"disabled":145,"type":2473},[14,2572,2573],{},"Runtime caching",[421,2575,2576,2581,2587],{},[424,2577,2578,2579,93],{},"API con estrategia ",[43,2580,723],{},[424,2582,2583,2584,2586],{},"Imágenes con ",[43,2585,729],{}," (máx. 30 días).",[424,2588,2589,2590,2592],{},"Fuentes con ",[43,2591,729],{}," (máx. 1 año).",[424,2594,2596,2474,2598,2601,2602,443,2604,2606],{"className":2595},[2469],[2471,2597],{"disabled":145,"type":2473},[14,2599,2600],{},"Limite de caché configurado"," (",[38,2603,2402],{},[38,2605,2405],{},").",[424,2608,2610,2474,2612,2615,2616,2619],{"className":2609},[2469],[2471,2611],{"disabled":145,"type":2473},[14,2613,2614],{},"Evitar recursos obsoletos"," → ",[38,2617,2618],{},"cleanupOutdatedCaches: true"," habilitado.",[19,2621],{},[52,2623,2625],{"id":2624},"_4-accesibilidad-y-ux","4. Accesibilidad y UX",[421,2627,2629,2638,2647],{"className":2628},[2465],[424,2630,2632,2474,2634,2637],{"className":2631},[2469],[2471,2633],{"disabled":145,"type":2473},[14,2635,2636],{},"Theme color definido"," → Se refleja en la barra de estado del dispositivo.",[424,2639,2641,2474,2643,2646],{"className":2640},[2469],[2471,2642],{"disabled":145,"type":2473},[14,2644,2645],{},"Background color definido"," → Pantalla de carga consistente al abrir la app.",[424,2648,2650,2474,2652,494,2655],{"className":2649},[2469],[2471,2651],{"disabled":145,"type":2473},[14,2653,2654],{},"Meta iOS",[421,2656,2657,2662],{},[424,2658,2659,2661],{},[38,2660,912],{}," disponible.",[424,2663,2664,917,2667,2670],{},[38,2665,2666],{},"mobile-web-app-capable",[38,2668,2669],{},"apple-mobile-web-app-capable"," configurado si necesitas soporte específico.",[19,2672],{},[52,2674,2676],{"id":2675},"_5-actualizaciones","5. Actualizaciones",[421,2678,2680,2700],{"className":2679},[2465],[424,2681,2683,2474,2685,494,2688],{"className":2682},[2469],[2471,2684],{"disabled":145,"type":2473},[14,2686,2687],{},"registerType configurado",[421,2689,2690,2695],{},[424,2691,2692,2694],{},[38,2693,756],{}," si quieres que todo se actualice en segundo plano.",[424,2696,2697,2699],{},[38,2698,762],{}," si prefieres notificar al usuario antes de actualizar.",[424,2701,2703,2474,2705,2708,2709,2711],{"className":2702},[2469],[2471,2704],{"disabled":145,"type":2473},[14,2706,2707],{},"Prueba de actualización"," → Haz un cambio en tu código, vuelve a hacer ",[38,2710,718],{}," y recarga la app: el SW debería actualizarse.",[19,2713],{},[52,2715,2717],{"id":2716},"_6-auditoría-completa","6. Auditoría completa",[10,2719,2720],{},"En Lighthouse (Chrome DevTools → Audits → PWA), revisa:",[421,2722,2724,2733,2742],{"className":2723},[2465],[424,2725,2727,2474,2729,2732],{"className":2726},[2469],[2471,2728],{"disabled":145,"type":2473},[14,2730,2731],{},"Fast and reliable"," (rápida y confiable).",[424,2734,2736,2474,2738,2741],{"className":2735},[2469],[2471,2737],{"disabled":145,"type":2473},[14,2739,2740],{},"Installable"," (instalable en dispositivos).",[424,2743,2745,2474,2747,2750],{"className":2744},[2469],[2471,2746],{"disabled":145,"type":2473},[14,2748,2749],{},"PWA Optimized"," (usa buenas prácticas).",[10,2752,2753],{},[14,2754,2755],{},"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.",[19,2757],{},[22,2759,2761],{"id":2760},"conclusión","Conclusión",[10,2763,2764,2765,2768,2769,2771,2772,2775],{},"Convertir tu proyecto ",[14,2766,2767],{},"Nuxt 4"," en una PWA con ",[38,2770,40],{}," es un proceso directo y altamente configurable. Definir un ",[38,2773,2774],{},"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.",[1090,2777,2778],{},"html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .sQeJH, html code.shiki .sQeJH{--shiki-light:#032F62;--shiki-default:#DBEDFF;--shiki-dark:#DBEDFF}html pre.shiki code .sAxt1, html code.shiki .sAxt1{--shiki-light:#22863A;--shiki-light-font-weight:bold;--shiki-default:#85E89D;--shiki-default-font-weight:bold;--shiki-dark:#85E89D;--shiki-dark-font-weight:bold}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}",{"title":62,"searchDepth":125,"depth":125,"links":2780},[2781,2784,2787,2791,2792,2793,2794,2795,2799,2800,2809],{"id":24,"depth":125,"text":25,"children":2782},[2783],{"id":54,"depth":142,"text":55},{"id":98,"depth":125,"text":99,"children":2785},[2786],{"id":418,"depth":142,"text":419},{"id":483,"depth":125,"text":2788,"children":2789},"3. Estrategias de Service Worker",[2790],{"id":706,"depth":142,"text":707},{"id":741,"depth":125,"text":742},{"id":893,"depth":125,"text":894},{"id":932,"depth":125,"text":933},{"id":964,"depth":125,"text":965},{"id":1606,"depth":125,"text":1607,"children":2796},[2797,2798],{"id":2322,"depth":142,"text":2323},{"id":2349,"depth":142,"text":2350},{"id":2387,"depth":125,"text":2388},{"id":2441,"depth":125,"text":2801,"children":2802},"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.",[2803,2804,2805,2806,2807,2808],{"id":2460,"depth":142,"text":2461},{"id":2517,"depth":142,"text":2518},{"id":2561,"depth":142,"text":2562},{"id":2624,"depth":142,"text":2625},{"id":2675,"depth":142,"text":2676},{"id":2716,"depth":142,"text":2717},{"id":2760,"depth":125,"text":2761},"22/01/2025","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.","md",null,"https://vite-pwa-org.netlify.app/icon_dark.svg",{},"/es/articles/5-amazing-raycast-nuxt-snippets",{"title":5,"description":2811},{"loc":2816},"es/articles/5-amazing-raycast-nuxt-snippets",[2821,2822,2823,2824],"Nuxt4","Vue","Vite","PWA","Vv0xhNELiWO3XBI80hkiHxETlUTMHKK8tMlOWm95c9I",1785160751296]