'Electron Differential updater produces large amounts of changed blocks even when minimal changes were done. Am I doing something wrong?

I'm working on a project built on Electron. We've set up for differential updates through electron-builder (with nsis-web, and a separate differential updater branch for mac), and were expecting it to produce small update downloads.

We're now realizing that the differential updates for our app (when packaged/zipped, the app is a total of ~100mb) tend to hover around ~20-40mb downloads, with somewhere around ~1000 changed blocks, even in cases where we've only changed 1 character in a string in our source code. As our userbase grows, and we foresee needs to quickly deploy updates, this can add up really fast for our server bills. We were expecting a fairly lower delta download, hopefully <=1mb for tiny changes such as a single character, rather than near half of the full app size.

We've built our app off of the Electron React Boilerplate, which uses webpack to pack up the source code.

We're currently obfuscating our webpack bundle, though this behaviour was also tracked to happen before obfuscation was added, so would rule it out as the cause.

I'm not clear if the 7z approach of blocks/file deltas would imply that a single change in a file could affect all its blocks, and if so, that breaking it up would mean that the blocks for unaffected files would then themselves be unaffected. (I'm still trying

We currently have a number of modules being imported into our project for various uses, which are getting packaged up into the final webpack bundle. I'm debating attempting to keep the modules external to the webpack bundle, but Electron's Performance page seems to advocate for bundling all the code together to avoid invoking expensive require() calls. I'm still trying to think of and try experiments to understand behaviour.

  1. Is there a way to obtain smaller differential downloads, or is this the actual expected delta size?

  2. If the former, are there some likely causes that we are doing wrong?

  3. Is there particular insight into the differential updater that would give better understanding of how to approach it?

Edit: Attempted a test where I only changed the app version, and the differential updater still logged this out:

[2021-10-14 18:29:34.046] [info] File has 2092 changed blocks
[2021-10-14 18:29:34.058] [info] Full: 95,995.56 KB, To download: 42,767.89 KB (45%)


Solution 1:[1]

Edit: This solution doesn't fully resolve issues for mac. It appears that native components are being modified even with only a version change for the mac package, causing them to generate large amounts of changed blocks.

Original answer below:

In short: disable Asar for the package.

I've identified some of the issues, chief of which was that differential updater in electron-builder uses 7zip to make the differential file, and from my understanding looking into it, 7zip generates an internal representation of the file structure.

Taking this into account, it turned out that disabling the ASAR file that is standard and recommended in Electron meant that all the source files where no longer combined inside it, allowing 7zip to individually track them. This means that any file changed appears to only affect the blocks for it in the blockmap. The ASAR file being a singular file seemed to make it so that any change in the source would modify the majority of the blocks for the ASAR file once 7zipped.

Additionally, this does appear to imply that more granular file structure in the Electron package would result in smaller deltas for the differential autoupdater.

Solution 2:[2]

That's the problem with differential updates. It uses compression blocks to update the app which is poor in terms of bandwidth usage. That's why a true delta updater like https://github.com/electron-delta/electron-delta is required. It's built using binary diffing and is capable to update the app just by downloading the delta.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Sandeep Acharya