PWA应用、移动端Chrome、强制重新加载缓存的JS文件

4

我有一个PWA应用程序,其中我正在使用Webpack渲染js文件:

{% render_bundle 'app' 'js' %}

在移动Chrome中启动PWA应用后,该文件未更新。很可能Chrome使用缓存的版本。我尝试删除PWA应用并重新安装它,但没有帮助。之后,我手动清除了移动Chrome缓存,并刷新了文件,然而,大多数用户不会这样做,所以我需要另一个解决方案,它不需要任何终端用户的操作。类似问题的回答建议给js文件添加参数或版本号。请参考此链接获取更多信息。
<script type="text/javascript" src="myfile.js?REVISION"></script>

然而,如何使用Webpack实现这一点尚不清楚?

另一个流行的答案解释了我可以使用hash或chunkhash来生成文件名:

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

这个解决方案对我不适用,因为每次文件更改时我无法更改文件名。文件名应保持不变,因为我使用django的collectfast应用程序。它检查静态文件的md5sum,并仅更新已更改的文件。

静态js文件的名称应保持不变。同时,我需要一种机制来强制移动Chrome更新更改的文件。


你遇到了什么错误? - abielita
@abielita,错误在于当我将新的JS文件上传到服务器时,在移动设备上的PWA应用程序中,此文件未得到更新。 - Alexander Tyapkov
如果您的应用程序由于多个公共模块而真正使用了多个块,_难道您不希望在每次构建时更新它们的内容吗_(这应该通过使用块哈希来确保)?请确认chunkhash在构建过程中是否会更改。我不熟悉这些配置,但我的印象是chunkhash不应在没有代码更改的情况下更改。如果它在没有代码更改的情况下更改,那可能表示另一个问题。请将这些观察结果添加到您的问题中。更多的配置信息也可能有所帮助。 - try-catch-finally
以下是一些类似的问答,你可能会从中获得一些想法(不确定是否重复):https://stackoverflow.com/questions/42829865/mix-long-term-caching-and-code-splitting-in-webpack-2/42830135 - try-catch-finally
@try-catch-finally 我认为我处理静态文件的内部工作流程与问题无关。我所描述的代码不会以任何方式更改静态文件。如果文件名没有更改,但文件本身发生了一些更改,我只需要一种方法来强制移动浏览器更新js文件。 - Alexander Tyapkov
显示剩余4条评论
3个回答

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;
                    }
                };
            };
        })
}

1

我试图在这里使用 Svelte PWA 代码完成同样的事情: https://github.com/kuhlaid/svelte2/releases/tag/v0.1.6

我通过运行应用程序构建过程,然后使用 'replace-in-file' 插件(请参见 rollup.config.js 脚本)来解决问题。如果您在源代码中搜索 '__cVersion__',则会看到我正在添加文件修订字符串以尝试强制执行文件缓存更新(而不是 localstorage)。

另一件需要为 PWA 完成的事情是确保我们清除用户浏览器中的 CacheStorage,如果您使用类似 Workbox 的东西来预缓存服务工作器中的文件,则必须这样做。由于清除 CacheStorage 的代码需要在浏览器中访问应用程序时运行,因此无法在构建过程中完成。要清除此缓存,您可以在应用程序的 javascript 中插入类似以下内容:

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)});
    });
  });
}

这很好,但是接下来的问题是如何仅在新代码构建/更新时执行一次?可能可以在您的javascript中添加一个“代码版本”变量,例如:

const codeVersion = __cVersion__;

在构建/打包代码期间,您需要动态替换__cVersion__为新的版本字符串(例如v0.112),并将此codeVersion值存储到应用程序的localStorage中。每次构建时,您都应首先检查localStorage中版本字符串是否有更改,如果已更改,则运行代码以删除应用程序的CacheStorage(如上所述)。我的PWA代码版本处理了这些情况: https://github.com/kuhlaid/svelte2/releases/tag/v0.1.7 自动清除终端用户的缓存是PWA(或任何应用程序)的复杂性之一,开发人员应该事先了解。没有人喜欢一个应用程序,开发人员告诉您每次推送代码更新时都需要手动清除浏览器缓存。

0
你可以尝试在你的HTML中加入以下代码,这将强制缓存过期。
<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" />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接