<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ivo Angaramo</title>
    <description>The latest articles on DEV Community by Ivo Angaramo (@ivo_angaramo_0c7934edc8cd).</description>
    <link>https://dev.to/ivo_angaramo_0c7934edc8cd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4097687%2Fc1996d04-ee1b-45c8-9583-7a7e22ce73f4.jpg</url>
      <title>DEV Community: Ivo Angaramo</title>
      <link>https://dev.to/ivo_angaramo_0c7934edc8cd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ivo_angaramo_0c7934edc8cd"/>
    <language>en</language>
    <item>
      <title>El bug que no era un bug: por qué tu PWA instalada nunca ve el fix que ya subiste</title>
      <dc:creator>Ivo Angaramo</dc:creator>
      <pubDate>Thu, 27 Aug 2026 15:29:30 +0000</pubDate>
      <link>https://dev.to/ivo_angaramo_0c7934edc8cd/el-bug-que-no-era-un-bug-por-que-tu-pwa-instalada-nunca-ve-el-fix-que-ya-subiste-101f</link>
      <guid>https://dev.to/ivo_angaramo_0c7934edc8cd/el-bug-que-no-era-un-bug-por-que-tu-pwa-instalada-nunca-ve-el-fix-que-ya-subiste-101f</guid>
      <description>&lt;p&gt;Arreglamos un bug de layout en el calendario de &lt;a href="https://formi.studio" rel="noopener noreferrer"&gt;Formi&lt;/a&gt;. Lo verificamos en local, contra el build de producción, con Playwright apuntando al sitio real — perfecto en los tres. Lo subimos.&lt;/p&gt;

&lt;p&gt;El usuario que reportó el bug lo siguió viendo. Exactamente igual.&lt;/p&gt;

&lt;p&gt;No era caché del CDN, no eran los hashes de los archivos (Vite les pone un hash distinto en cada build, eso ya estaba bien resuelto). El problema era más aburrido y más traicionero: tenía la app &lt;strong&gt;instalada como PWA&lt;/strong&gt;, y una PWA instalada no se comporta como una pestaña del navegador — nadie la "refresca". El usuario la abre desde el ícono, ve la última versión que el Service Worker tiene cacheada, y listo. Si ese Service Worker nunca se entera de que hay uno nuevo, la app queda congelada en el tiempo — para siempre, hasta que alguien la desinstale y reinstale a mano.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por qué pasa esto
&lt;/h2&gt;

&lt;p&gt;Un Service Worker no se actualiza solo por arte de magia. El navegador lo chequea en background en algunos casos (navegación completa, cierre y reapertura de pestaña), pero una PWA que vive en la pantalla de inicio y se abre/cierra todo el tiempo sin recargar nunca dispara esos chequeos. Necesitás pedírselo vos, explícitamente, en el momento correcto.&lt;/p&gt;

&lt;h2&gt;
  
  
  La solución (3 piezas)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Versionar el Service Worker en cada build&lt;/strong&gt;, no solo tus assets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite-plugin-sw-version.js — corre en cada `vite build`&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`myapp-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// reemplaza un placeholder en sw.js por este string único&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sin esto, aunque el navegador chequee, va a ver "el mismo" &lt;code&gt;sw.js&lt;/code&gt; de siempre y no va a descargar nada nuevo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Pedirle al navegador que chequee, activamente, cada vez que la app vuelve a primer plano:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkForUpdate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;reg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;visibilitychange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;visibilityState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;checkForUpdate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;focus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;checkForUpdate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Cuando encuentra una versión nueva, que tome control de inmediato y recargue solo&lt;/strong&gt; (en vez de esperar a que el usuario cierre todas las pestañas, que en una PWA instalada puede no pasar nunca):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// en sw.js: self.skipWaiting() en 'install', self.clients.claim() en 'activate'&lt;/span&gt;

&lt;span class="c1"&gt;// del lado del cliente:&lt;/span&gt;
&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;controllerchange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  El detalle molesto
&lt;/h2&gt;

&lt;p&gt;Si tu PWA ya está instalada en el celular de alguien &lt;strong&gt;sin&lt;/strong&gt; este mecanismo, necesita reinstalarse &lt;strong&gt;una única vez&lt;/strong&gt; para que el mecanismo nuevo entre en juego. Es la única vez que vas a tener que pedirle a un usuario que desinstale/reinstale — de ahí en adelante, cada deploy se actualiza solo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Probalo
&lt;/h2&gt;

&lt;p&gt;Armé las tres piezas como paquete de npm, sin dependencias, funciona con Vite + cualquier framework:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;pwa-auto-update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Código y detalles: &lt;a href="https://github.com/ivoangaramo-ux/formi-oss/tree/main/pwa-auto-update" rel="noopener noreferrer"&gt;github.com/ivoangaramo-ux/formi-oss/tree/main/pwa-auto-update&lt;/a&gt;&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>vite</category>
    </item>
  </channel>
</rss>
