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