What is the best way to retrieve the version hash of the current Angular PWA?

Is there a way to retrieve the currently active hash of my Angular PWA without waiting for an event trigger?

While the SwUpdate object offers observables for accessing the hash when a new version is activated or becomes available, it does not seem to provide a method for getting the hash of the current version statically.

class SwUpdate {
  available: Observable<UpdateAvailableEvent>
  activated: Observable<UpdateActivatedEvent>
  unrecoverable: Observable<UnrecoverableStateEvent>
  isEnabled: boolean
  checkForUpdate(): Promise<void>
  activateUpdate(): Promise<void>
}

I am looking for something like SwUpdate.current to get the current hash value (e.g.

a518f9f1ab65954c2eafa02fec134fa54b391651
) without relying on an available or activated event. Is this feasible?

Addendum

Although I couldn't find a solution through official channels, I managed to address this issue by creating a custom hash version for the app during the CI build process. This was stored in a JSON file within the app and used as the app version's hash instead of the Angular-generated one. So far, this workaround has been effective.

Answer №1

To implement automatic updates in your Angular application, you can utilize the SwUpdate module from @angular/service-worker. A common way to do this is by checking for updates in the main component file, such as app.component.ts:

import { Component, OnInit } from '@angular/core';
import { SwUpdate } from '@angular/service-worker';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {

  constructor(private swUpdate: SwUpdate) {}

  checkForUpdate() {
    if (this.swUpdate.isEnabled) {
      this.swUpdate.available.subscribe((event) => {
        console.log('Update is available!');
        console.log('Current version: ' + event.current.hash);
        console.log('New available version: ' + event.available.hash);
      });
    }
  }

  ngOnInit() {
    this.checkForUpdate();
  }
}

Answer №2

I encountered a similar issue and was unable to locate a solution online. It puzzles me why Angular does not offer this information straightforwardly. Thus, I delved into experimentation until I stumbled upon a potential workaround. The application data and its versions are stored in the cache:

https://i.sstatic.net/2fNZ78tM.png

Specifically, the hash of the most recent saved version can be found at the /latest path, and it can be retrieved using this method:

caches.open('ngsw:/:db:control').then((cache) => {
  cache.match('/latest').then((res) => {
    res?.json().then((body) => {
      console.log(body.latest)
    }
  }
}

I also wanted to fetch the version date, so I examined the manifest of that version and transformed it into an observable using the "from" operator from rxjs to prevent it from resolving as a promise:


    import { from } from 'rxjs';

    getAppVersion() {
        return from(
          caches.open('ngsw:/:db:control').then((cache) => {
            return cache.match('/latest').then((resLts) => {
              return resLts?.json().then((bodyLts) => {
                return cache.match('/manifests').then((resManifests) => {
                  return resManifests?.json().then((manifests) => {
                    return {
                      hash: bodyLts.latest,
                      timestamp: manifests[bodyLts.latest].timestamp,
                    };
                  });
                });
              });
            });
          })
        );
      }

This is the extent of my progress, and while I am content with the outcome, there is an issue wherein the cache may not exist on the initial site load, resulting in no return value. Perhaps periodic queries could be implemented until the necessary information is obtained, but I am uncertain of its effectiveness.

Furthermore, there is a concern that this solution may only be temporary since there is no official documentation in Angular indicating the permanence of these cache routes.

Despite the age of this question, I felt it was valuable to share in case it proves beneficial to others.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Customize the theme type with @mui/system

Is there a way to customize my theme settings in @mui/system? While using the sx prop in Stack, the theme is defined in createTheme.d.ts, but it seems like there isn't an option to extend or override it. To work around this limitation, I have been u ...

Angular, Bootstrap, and the magic of routing

I have created a menu along with breadcrumbs using components and their children. The issue arises when I try to view the grandchildren of a component; they appear under their parent component. My aim is to display only the child component without the pa ...

The nest build process encounters errors related to TypeScript in the @nestjs/config package, causing it

Encountering several issues related to @nestjs/config, causing the npm build command to fail. However, npm run start:dev is still functional despite displaying errors. See below for screenshots of the errors and environment: https://i.sstatic.net/Wxkkn.png ...

Finding the specific type within a union based on its field type

I am trying to implement a function sendCommand that returns a value of type specified by the union InputActions, selected based on the action_id type. Below is my code snippet: interface OutputAction1 { command: 'start', params: string; } i ...

What is the best way to create a type that can accept either a string or a

I'm working with a map function and the parameter type is an array of strings or numbers. I've defined it as: (param: (string | number)[]) => ... However, I want to simplify it to: (param: StringOrNumber)[]) => ... Having to repeat the ...

Incorporating items into a mat-tab-group component

Using Angular 5 to Create a Search Bar I am looking for a way to add a search bar to the header of a mat-tab-group element. Is it possible to display an element that is not a tab, like an image, within a mat-tab-group element? ...

Stars not functioning in Firefox for CSS Angular2 ng2-rating component

Recently, I've been utilizing the ng2-rating module found at https://www.npmjs.com/package/ng2-rating. However, an intriguing issue has arisen specifically in Firefox - a mysterious gap between the filled stars and empty stars. Strangely enough, this ...

Issue with creating a new component in Angular cli

I encountered an issue while trying to generate "app1/probangif" with the command ng generate. The error message displayed was: "An unhandled exception occurred: Schematic 'app1/probangif' not found in collection '@ngrx/schematics'." ...

Webpack is mistakenly looking in the incorrect subfolder when attempting a relative import

I have set up a Vue application (version 3 with TypeScript) within a directory structure where the Vue app is nested inside a directory named /my-vue-app. In the same directory, there is a folder containing my Node.js server code (not TypeScript) that I am ...

How to limit character input in a Div using Angular 2

I need some guidance on Angular 2 with TypeScript. I want to apply a validation rule to a "Div" element where the maximum length should be set to 100 characters. Additionally, even when text is copied and pasted into the Div, it should not exceed 100 chara ...

Implementing routing for page navigation within an angular tree structure

Can someone assist me with integrating a route into an angular tree structure? Here is the HTML code snippet: <mat-tree [dataSource]="dataSource" class="tree-container" [treeControl]="treeControl"> <mat-tree-node class="btnLinks" *matTreeN ...

What is the best way to swap out the if else statement with a Ternary operator within a JavaScript function?

Is there a way to replace the if else statement in the function using a Ternary operator in JavaScript? private getProductName(productType: string): string { let productName = 'Product not found'; this.deal.packages.find(p => p.isSele ...

Efficiently Updating Property Values in Objects Using TypeScript and Loops

I have been looking into how to iterate or loop through a code snippet, and while I managed to do that, I am facing an issue where I cannot change the value of a property. Here is the snippet of code: export interface BaseOnTotalPaidFields { groupName ...

Encounter problem following transition from Angular 7 to Angular 8 upgrade

After updating a project from Angular 7 to Angular 8, I encountered an error when trying to build for production. The error message reads as follows: ERROR in app/app.component.ts:7:36 - error TS2307: Cannot find module '@angular/router/src/route ...

Angular's error notification system seems to be lacking in providing accurate

I'm experiencing an issue with my angular app where errors are not displayed properly. Instead of showing errors in the component and line number, they always appear in main.js. This is different from how errors are displayed in my other angular appli ...

Guide on implementing Bootstrap tooltips using Bootstrap's *Content Delivery Network* in Angular

I have added bootstrap.min.css and bootstrap.min.js to my Angular project's index.html. I want to utilize Bootstrap tooltips, but I'm unsure how to do it without needing to npm install bootstrap Here is the element you can add a tooltip to: < ...

Utilizing NgRx 8 Actions in Conjunction with NgRx 7 Reducers: An Implementation

In the development of my new Angular 8 project, I have incorporated the NgRx library. It was mentioned to me that actions are created using createAction in NgRx 8, but reducers are built using NgRx 7. Initially, I implemented my reducer with NgRx 8, but no ...

What is the syntax for creating a function with parameters of type `any` or `void` in TypeScript?

How can I create a function in typescript that accepts either something or nothing as input? I attempted the following: interface TestFn { (input: any | void): string } const operation: TestFn = (input) => 'result'; operation('some ...

Issue with TypeScript: The JSX element 'MultiSelect' lacks any construct or call signatures

I have integrated the react-multi-select-component package from this source This is my current implementation: import React, { ReactElement, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import Constants fro ...

Attempting to categorize JSON object elements into separate arrays dynamically depending on their values

Here's the JSON data I'm currently working with: ?$where=camis%20=%2230112340%22 I plan to dynamically generate queries using different datasets, so the information will vary. My main objective is to categorize elements within this array into ...