4

I have PWA app in which I am rendering js files using Webpack:

{% render_bundle 'app' 'js' %}

After launching the PWA app in mobile Chrome the file is not updated. Most probably Chrome uses cached version.

I tried to delete PWA app and install it again but it did not help.

Afterwards I have cleared the mobile Chrome cache manually and files were refreshed, however, most of the users won't do it so I need another solution which does not require any actions from end users.

Answers on similar question suggest to add parameter or version number to the js file.

<script type="text/javascript" src="myfile.js?REVISION"></script>

However, it is not clear how can I do it using Webpack?

One more popular answer explains that I can use hash or chunkhash to generate file name using Webpack:

output: {
    path: '/',
    filename: '[hash].js',
    chunkFilename: '[chunkhash].js',
},

This solution won't work for me because I cannot change the name of the file every time when there are some chnages in it. The name of the file should stay the same because I use django's collectfast app. It checks the md5sum of static files and updates only those ones which have been changed.

The name of the static js file should stay the same. At the same time, I need mechanism which will force mobile Chrome to update changed file.

Alexander Tyapkov
  • 4,837
  • 5
  • 39
  • 65
  • What error have you encountered? – abielita Feb 18 '18 at 15:08
  • @abielita the error is that when I upload new js file to the server, this file is not updated in PWA app at mobile device. – Alexander Tyapkov Feb 18 '18 at 15:10
  • If your application really makes use of multiple chunks due to multiple common modules _don't you want them to be updated on every build if their contents change_ (which should be ensured by using chunk hashes)? Please confirm that the `chunkhash` does (not) change during builds. I'm not familiar with these configs but I'm under the impression that `chunkhash` should not change without code changes. If it does change without code changes that might indicate another problem. Please add such observations to your question. A bit more of the config may help too. – try-catch-finally Feb 24 '18 at 06:17
  • Similar Q&A you may gain ideas from (not sure whether or not it's a duplicate): https://stackoverflow.com/questions/42829865/mix-long-term-caching-and-code-splitting-in-webpack-2/42830135 – try-catch-finally Feb 24 '18 at 06:18
  • @try-catch-finally yes, good point. I am really updating chunks when they are changed but at the same time I don't want to update their names. The reason is that I am using internal solution (without webpack) which calculates md5sum for each file. Names of the files are then used as indentifiers and should stay the same. – Alexander Tyapkov Feb 24 '18 at 07:34
  • @try-catch-finally If I use hash or chunkhash, then names will be changed either on every files compile or when some files are changed. Both scenarios won't fit me. – Alexander Tyapkov Feb 24 '18 at 07:44
  • You should definitively _describe the "internal solution"_ and the process using it (edit your question). Use data flow diagrams or pseudo code. At the moment your question is not clear enough. You can't ask questions on a specific technology when your problem actually is part of your own code which you don't provide. ;) And: edit rather than comment. – try-catch-finally Feb 24 '18 at 10:05
  • @try-catch-finally I think the internal workflow of how I handle static files is not related to the question. The code which I have described doesn't change static files in any way. I just need the way to force mobile browser update js file if there is NO change in file name, but there are some changes in the file itself. – Alexander Tyapkov Feb 24 '18 at 13:12
  • The only practical solution is to not use the PWA. Use the Chrome version (normal website) and reload from the inspector after connecting the phone to the PC via chrome://inspect/#devices – Federico Schiocchet Mar 08 '22 at 20:00

3 Answers3

1
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('service-worker.js')
        .then(reg => {
            reg.onupdatefound = () => {
                const installingWorker = reg.installing;
                installingWorker.onstatechange = () => {
                    switch (installingWorker.state) {
                        case 'installed':
                            if (navigator.serviceWorker.controller) {
                                // new update available
                                setTimeout(() => document.location.reload(true), 1000);
                                caches.keys().then(keys => {
                                    keys.forEach(key => caches.delete(key));
                                })
                            }
                            break;
                    }
                };
            };
        })
}
jales cardoso
  • 591
  • 7
  • 11
1

I was trying to do the same thing with Svelte PWA code here: https://github.com/kuhlaid/svelte2/releases/tag/v0.1.6

I resorted to running the app build process and then using the 'replace-in-file' plugin (see the rollup.config.js script). If you search the source code for '__cVersion__' you will see where I am adding the file revision string to try and force a file cache update (not localstorage).

The OTHER thing that needs to be done for a PWA is making sure we clear the CacheStorage in the users browser if you are building your service working with something like Workbox to precache files within the service worker. This is something you are NOT ABLE to do during the build process since the code to clear the CacheStorage needs to be run at time of accessing the app in the browser. To clear this cache you can insert something along these lines in the javascript of your app:

const l = console.log    
if ('caches' in window) {
  l('CacheStorage is present for this app');
  caches.keys().then(function(cacheArray) {
    l(cacheArray); // just print the list of CacheStorage names to the console
    // for each cache, try and delete it
    cacheArray.forEach(function(cache) {
      caches.delete(cache).then((bool) => {
        l('deleted cache: '+cache); // print the successful deletion to console
      }).catch((err) => {l(err)});
    });
  });
}

This is all well and good, BUT this begs the next question of how you only execute this ONCE for a new code build/update? Well, possibly a 'code version' variable could be added to your javascript somewhere like:

const codeVersion = __cVersion__;

Then during the build/rollup of your code, you dynamically replace __cVersion__ with your new version string (eg. v0.112) and store this codeVersion value to localStorage for the app. Then each time you build you would check localStorage first for a change in the version string, and if it has changed then run the code to delete the CacheStorage for the app (as mentioned above). This version of my PWA code handles these cases: https://github.com/kuhlaid/svelte2/releases/tag/v0.1.7

Automatically clearing the cache for end-users is one of the complexities of PWA (or any app) that should be understood upfront by the developer. No one likes an app where you are told by the developer that YOU need to manually clear your browser cache each time they push a code update.

w. Patrick Gale
  • 1,643
  • 13
  • 22
0

you could try putting one of these in your html, that would force cache to expire.

<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />