question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Provide a way to know whether something really did change when we receive the update available event from the service worker

See original GitHub issue

Which @angular/* package(s) are relevant/releated to the feature request?

service-worker

Description

I am developing an Angular PWA that is served by the backend application. Each time something changes in the application (whether it is in the backend or in the frontend), the CI builds from scratch.

If nothing changed in the frontend since the latest build, the build output is the same as the previous one. In this case, I don’t want my users to get an update available because there will be nothing new. But unfortunately when the build input is the same, the build output is not exactly the same: the build timestamp is updated in the ngsw.json file (and that makes sense).

In this case I receive an update available event (which can make sense on a technical point of view) but not really in the user experience one. The UpdateAvailableEvent does not seem to expose anything that enables to know whether the application really did change.

I looked for a solution to this issue on StackOverflow and GitHub and did not find anything. Please let me know if a solution already exists for this issue.

Proposed solution

It can make sense to receive the update available event in this case, but that would be nice to have some extra information regarding the current and the available versions.

For now, we only have the version hash (which is different in this case, so I assume it takes the ngsw.json file into account) and the appData field that is undefined.

If we could have access to the hashTable field of the ngsw.json, I guess we could know whether something really did change by comparing them. A helper method that directly tells whether something did change would be even better in my case (I don’t care about the hashes as far as I know whether something changed or not).

Alternatives considered

I don’t see any alternative, sorry.

Thanks!

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:3
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
gkalpakcommented, Sep 13, 2021

Thx for the very clear explanation, @bsautel 👍

To give some background, the timestamp property was specifically added in order to differentiate versions of the app that comprise the exact same files/content but are built at different points in time. You can find out more about the reasoning and the problem this is addressing in 586234bb0197ad21b2a6efe8612ad1cfdecaba39 (and the associated issue).

Theoretically, it would be possible for the SW for compute two hashes for each app version in the UpdateAvailableEvent (one corresponding to the whole ngsw.json content and one corresponding to the same content but ignoring the timestamp property). However, I believe this might not be utilized by many people, but it would unnecessarily complicate the API surface.

I am happy to leave this open as a feature request and see how many upvotes it gets, though.

In the meantime, you can implement something similar using the appData property. I.e. you could have a post-build script that updates the generated ngsw.json to add an appData field with the hash of the ngsw.json content without the timestamp. You could then use it on the client to compare the appData values of the two versions mentioned in an UpdateAvailableEvent and decide whether to show a message or not.

The script could look something like this:

// Imports
const {createHash} = require('crypto');
const {copyFileSync, readFileSync, writeFileSync} = require('fs');

// Constants
const DIST_DIR = 'dist/my-app';
const NGSW_PATH = `${DIST_DIR}/ngsw.json`;
const NGSW_BACKUP_PATH = `${NGSW_PATH}.bak`;

// Run
copyFileSync(NGSW_PATH, NGSW_BACKUP_PATH);                    // Back up the generated manifest (just in case).

const ngswObj = JSON.parse(readFileSync(NGSW_PATH, 'utf8'));  // Load the generated manifest.
const {timestamp, ...ngswObjWithoutTs} = ngswObj;             // Get a copy without `timestamp`.
const ngswHashWithoutTs = createHash('sha1').
  update(JSON.stringify(ngswObjWithoutTs)).
  digest('hex');                                              // Compute the hash for the copy.

const appData = ngswObj.appData || (ngswObj.appData = {});    // Get or add the `appData` object.
appData.manifestHashWithoutTimestamp = ngswHashWithoutTs;     // Update `appData` with the hash.

writeFileSync(NGSW_PATH, JSON.stringify(ngswObj, null, 2));   // Write the updated manifest to file.
1reaction
bsautelcommented, Sep 13, 2021

Many thanks @gkalpak for your quick answer, your explanation and even the script. 😊

I did not notice that the appData field of the update available event was coming from the ngsw.json file’s appData one. Knowing that, your suggested workaround totally makes sense. I tested it and I can confirm that it enabled me to do what I wanted. 👍‍

Thanks once again to you, all the Angular team and the community. You build a very good tool!

Read more comments on GitHub >

github_iconTop Results From Across the Web

How: ServiceWorker check if ready to update - Stack Overflow
when service worker is active you cannot check for updates by evaluating some code in SW - this is still the same cached...
Read more >
Handling Service Worker updates – how to keep the app ...
By ensuring our update UX is only triggered when we're sure there's a Service Worker instance visible under registration.waiting (successfully installed, ...
Read more >
The service worker lifecycle - web.dev
Your service worker is considered updated if it's byte-different to the one the browser already has. (We're extending this to include imported ...
Read more >
Using Service Workers - Web APIs | MDN
After activation, the service worker will now control pages, but only those that were opened after the register() is successful. In other words, ......
Read more >
How to display a "new version available" of your Progressive ...
In this article, I will show you how to add a notification to your site and display it each time that there is...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found