Blog Técnico
20 de septiembre de 2022
Jhonatan Estiven Becerra Pedrozo
5 min lectura
Caché Angular

Resolviendo el Problema de la Caché en Aplicaciones Web: Mi Solución

¡Hola a todos! Hoy quiero compartir una solución que desarrollé para abordar un problema común pero molesto en las aplicaciones web: la caché. La caché puede ser un dolor de cabeza, especialmente cuando los usuarios ven una versión desactualizada de la aplicación, lo que puede dar lugar a casos falsos o experiencias de usuario frustrantes.

El Desafío

Mi empresa se enfrentaba a este problema y necesitábamos una solución que fuera general, fácilmente integrable en nuestras aplicaciones y que nos permitiera mantener el control de las versiones de la aplicación en producción.

La Solución

Desarrollé un servicio que realiza una solicitud HTTP que sale de la aplicación para volver y encontrar un archivo .json con información de versionado. Este archivo se compara con otro archivo .ts importado en el servicio, esta es el que se queda “pegado” en la caché. Permítanme explicar cómo funciona:

  1. Archivos de versionado: crea dos archivos, uno .json y otro .ts.

config.json

{
  "version": "1.0.0"
}

config_version.ts

export const config_version = {
  version: "1.0.0",
};
  1. Crea un servicio cache.service.ts: en el servicio cache.service.ts vas realizar una petición http que sale de la aplicación para volver y si hay diferencia entre el resultado de la petición a config.json contra la importación de la versión condig_version.ts vas a hacer reload de la app.

cache.service.ts

import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { config_version } from "@assets/config_version";
import { CanActivate } from "@angular/router";
import { ToastrService } from "ngx-toastr";

@Injectable({
  providedIn: "root",
})
export class CacheService implements CanActivate {
  constructor(
    private httpClient: HttpClient,
    private toastrService: ToastrService
  ) {}

  canActivate(): boolean {
    this.getCache();
    return true;
  }

  getCache() {
    const headers = new HttpHeaders()
      .set("Cache-Control", "no-cache")
      .set("Pragma", "no-cache");

    return this.httpClient
      .get<any>(`assets/config.json`, { headers })
      .subscribe((config) => {
        if (config.version != config_version.version) {
          this.toastrService.warning(
            "Se ha detectado una nueva versión de la aplicación, se actualizará en breve.",
            "Actualización",
            {
              progressBar: true,
              progressAnimation: "increasing",
              positionClass: "toast-bottom-full-width",
              timeOut: 6000,
            }
          );
          setTimeout(() => {
            window.location.reload();
          }, 7000);
        }
      });
  }
}

La Integración

Para hacer que esta solución sea lo más general posible y evitar la necesidad de integrar código en cada controlador que utilice el servicio, implementé un guardián canActivate en las rutas que requieren esta validación. Los guardianes actúan como middlewares y se ejecutan cada vez que intentamos cambiar de vista dentro de la aplicación. Esto garantiza que la verificación del versionado sea parte integral de la navegación en la aplicación.

  1. Integrar a app-routing.module.ts: Agrega el guardian canActivate a las rutas pasandole el servicios cache.service.ts.

app-routing.module.ts

import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { CacheService } from "./services/cache.service";
const routes: Routes = [
  {
    path: "",
    canActivate: [AuthGuardService],
    component: InicioComponent,
  },
  {
    path: "inicio-sesion",
    canActivate: [AuthGuardLoginService, CacheService], //CacheService en canActive
    component: InicioSesionComponent,
  },
  {
    path: "**",
    redirectTo: "",
  },
];

@NgModule({
  imports: [RouterModule.forRoot(routes, { useHash: true })],
  exports: [RouterModule],
})
export class AppRoutingModule {}

Conclusión

El problema de la caché puede ser uno de los más tediosos en el desarrollo de aplicaciones web, y encontrar soluciones efectivas puede ser un desafío. Espero que esta solución que compartí hoy sea útil para la comunidad. No pretendo venderla comercialmente, simplemente quiero aportar una solución que funcionó para nosotros y que puede ayudar a otros a evitar problemas de caché y mantener sus aplicaciones actualizadas. ¡Hagamos que la experiencia del usuario sea siempre la mejor posible!

Si tienen alguna pregunta o comentarios, no duden en compartirlos. ¡Juntos podemos mejorar nuestras aplicaciones web y hacer que la web sea un lugar mejor para todos!

¿Te gustó este post?

Comparte tus ideas y comentarios. Siempre estoy abierto a discutir sobre tecnología y desarrollo.