Progressive Web Apps con Angular - Yessica54/carrera-front-end GitHub Wiki

Progressive Web Apps con Angular

Que son las PWA

Una Progressive Web App o PWA aúna lo mejor de una página web y de una aplicación nativa, ofreciendo grandes beneficios tanto al usuario como al dueño del sitio web. Su versatilidad y naturaleza progresiva aseguran una experiencia móvil perfecta desde cualquier dispositivo y sistema operativo.

Algunas metricas

55% de usuarios abandona un sitio si este no carga en 3 segundos La mayoria de sitios tarad 19 segundos en cargar Sitios que cargan dentro de los 5segundos aumentan su objetivo

Apps vs Mobile Web

La mayoría de nuestros usuarios consumen el contenido en mobile, Sin embargo la retención es mayor en Apps

Características:

  • Funciona Offline
  • Speed ( Uso de cache)
  • Push Notifications
  • Web Based
  • Deep Links ( Open App Using link) is easy to use in web, already use url/
  • Small bundle.
  • Easy to release and update.
  • Desktop Icon

Un service worker

Un service worker es una secuencia de comandos que tu navegador ejecuta en segundo plano, separado de una página web, abriéndoles la puerta a funciones que no necesitan una página web ni interacción de usuario.

Comando agregar pwa

ng add @angular/pwa

Pruebas con Lighthouse

Es una herramienta de auditoria para pwa

Caché de assets

Para los assest caché hay dos forma de instalacion o actualizacion, esto se hace en el archivo de configuración ngsw-config.json

  • lazy: a medida que el usuario va necesitando lso assest va cargandolos en cache
  • prefetch: Toma todos los archivos assests y lo guarda en cache de una vez.

Caché de requests

Al igual que los caches de los assets en el archivo de configuración ngsw-config.json, se debe agregar la configuración para para las API, ejemplo de esto:

"dataGroups": [ { "name": "api", "urls": ["https://platzi-store.herokuapp.com/**"], "cacheConfig": { "maxSize": 3, --> numeros de request que guarda "maxAge": "5m", --> Timpo de guarda cache "strategy": "freshness",--> freshness: si no puede ir a internet lo trae de cache, performance: si esta en cache lo trae "timeout": "2s" --> tiempo de espera } } ]

Enviando actualizaciones

Se utiliza la clase https://angular.io/api/service-worker/SwUpdate ejemplo

  import { SwUpdate } from '@angular/service-worker';

@Component({
  selector: 'app-root',
  template: '<router-outlet></router-outlet>',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
   constructor(
    private swUpdate: SwUpdate,
  ) {
  }
  
  ngOnInit() {
    this.updatePWA();
  }

  updatePWA() {
    this.swUpdate.available
    .subscribe(value => {
      console.log('update:', value);
      window.location.reload();
    });
  }
}

Implementando flujo de notificaciones

Se debe incluir los modulos de angularFire para incluir las notificaciones push

import { AngularFireModule } from '@angular/fire';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFireStorageModule } from '@angular/fire/storage';
import { AngularFireMessagingModule } from '@angular/fire/messaging';
import { AngularFirestoreModule } from '@angular/fire/firestore';

@NgModule({
  declarations: [
    AppComponent,
    LayoutComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    SharedModule,
    CoreModule,
    BrowserAnimationsModule,
    HttpClientModule,
    AngularFireModule.initializeApp(environment.firebase),
    AngularFireAuthModule,
    AngularFireStorageModule,
    AngularFireMessagingModule,
    AngularFirestoreModule,
    ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })
  ],
  providers: [],
  bootstrap: [AppComponent]

Es necesario obtener los permisos del usuario y se realiza una solicitud de token, se debe crear un método que escuche la notificacion

import { Component, HostListener, OnInit } from '@angular/core';
import { AngularFireMessaging } from '@angular/fire/messaging';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';

interface Token {
  token: string;
}

@Component({
  selector: 'app-root',
  template: '<router-outlet></router-outlet>',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {

  private tokensCollections: AngularFirestoreCollection<Token>;

  constructor(
    private messaging: AngularFireMessaging,
    private database: AngularFirestore
  ) {
    this.tokensCollections = this.database.collection<Token>('tokens');
  }

  ngOnInit() {
    this.requestPermission();
  }
 
  requestPermission() {
    this.messaging.requestToken
    .subscribe(token => {
      console.log(token);
      this.tokensCollections.add({token});
    });
  }

  listenNotifications() {
    this.messaging.messages
    .subscribe(message => {
      console.log(message);
    });
  }
}

Se debe agregar las configuraciones de las notificaciones de push de firebase

export const environment = {
  production: false,
  url_api: 'https://platzi-store.herokuapp.com',
  firebase: {
    apiKey: 'AIzaSyCehjKaeCl1j35pAId6TId-L2YdBQqKvSI',
    authDomain: 'angular-pwa-platzi.firebaseapp.com',
    databaseURL: 'https://angular-pwa-platzi.firebaseio.com',
    projectId: 'angular-pwa-platzi',
    storageBucket: 'angular-pwa-platzi.appspot.com',
    messagingSenderId: '1011695246249',
    appId: '1:1011695246249:web:1f9c4802a5cdff9c8842b8'
  }
};

Se debe crear el archivo firebase-messaging-sw.js dentro de src con el siguiente contenido

// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here, other Firebase libraries
// are not available in the service worker.
importScripts('https://www.gstatic.com/firebasejs/7.6.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/7.6.0/firebase-messaging.js');

// Initialize the Firebase app in the service worker by passing in the
// messagingSenderId.
firebase.initializeApp({
  	apiKey: "AIzaSyC5VMt0DoEcDA_RNaQXX1wUpc0yKg2G_z4",
    authDomain: "newtp-200719.firebaseapp.com",
    databaseURL: "https://newtp-200719.firebaseio.com",
    projectId: "newtp-200719",
    storageBucket: "newtp-200719.appspot.com",
    messagingSenderId: "359003727463",
    appId: "1:359003727463:web:cb1c8b960eb185658696c2"
});

// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();

Adiccionalmente agregar en angular.json a la compilación en assets

"assets": [
             "src/favicon.ico",
             "src/assets",
             "src/manifest.webmanifest",
             "src/firebase-messaging-sw.js"
           ],

Aplicando Lighthouse Bot a tu proceso de integración continua

Se instala el paquete npm install -g lighthouse, para la configuracion basica se ejecuta el comando lighthouse url, para la resto de la configuración ver la documentacion

⚠️ **GitHub.com Fallback** ⚠️