VueJS /浏览器缓存生产版本

html HTML

2020-03-12

我有一个VueJS应用。每当我运行npm run build它时,它都会创建一组新dist/*文件,但是,当我将它们加载到服务器上(删除旧版本后),并在浏览器中打开页面时,它将加载旧版本(我认为是从缓存中加载)。当我刷新页面时,它加载新代码没问题。

这是我的index.html:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
        <meta http-equiv="cache-control" content="max-age=0" />
        <meta http-equiv="cache-control" content="no-cache" />
        <meta http-equiv="expires" content="-1" />
        <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
        <meta http-equiv="pragma" content="no-cache" />
        <link rel="stylesheet" href="/static/css/bootstrap.min.css"/>
    </head>
    <body>
        <div id="app"></div>
    </body>
</html>

有没有一种方法可以强制它每次都加载新代码,或者(理想情况下)检查旧文件是否已从服务器中删除,然后刷新浏览器?

第975篇《VueJS /浏览器缓存生产版本》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

4个回答
GO西里 2020.03.12

基于对缓存头的综合回答,如果可以控制,最好的办法是在服务器端解决此问题,因为<meta>标记中的任何内容都将被服务器设置的头所覆盖。

对问题的评论表明您正在使用Nginx来提供此应用程序。使用上面的链接答案,我可以在我的nginx配置中为以这种方式结束的任何文件请求设置Cache-ControlExpiresPragma标头.html

server {

  ...other config

  location ~* \.html?$ {
    expires -1;
    add_header Pragma "no-cache";
    add_header Cache-Control "no-store, must-revalidate";
  }
}

这成功地迫使浏览器index.html在每次重新加载页面时请求最新的消息,但是除非最新的html响应中没有新的引用,否则仍然使用缓存的资产(js / css / fonts / images)。

AEva伽罗 2020.03.12

要删除缓存,您可以运行 rm -rf node_modules/.cache

这将删除您的缓存。您可以在部署之前运行新版本。

我在运行生产版本时遇到了同样的问题,但是即使在本地运行时,我的代码也将指向生产版本,而不是我的最新更改。

我相信这是一个相关的问题:https : //github.com/vuejs/vue-cli/issues/2450

逆天乐 2020.03.12

如果您使用asp.net core,则可以在webpack中尝试以下技巧,该webpack生成js文件,其名称末尾带有哈希值。my-home-page-vue.30f62910.js因此,您的index.html包含: <link href=/js/my-home-page-vue.30f62910.js rel=prefetch>这意味着只要您更改my-home-page.vue它,它就会在文件名中生成一个新的哈希。

The only thing you need is to add a cache restriction against the index.html

In your Startup.cs:

public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
    // ....
    app.UseStaticFiles(new StaticFileOptions
    {
      // Make sure your dist folder is correct
      FileProvider = new PhysicalFileProvider(Path.Combine(_env.ContentRootPath, "ClientApp/dist")),
      RequestPath = "",
      OnPrepareResponse = context =>
      {
        if (context.Context.Request.Path.StartsWithSegments("/index.html", StringComparison.OrdinalIgnoreCase))
        {
          context.Context.Response.Headers.Add("Cache-Control", "no-cache, no-store");
          context.Context.Response.Headers.Add("Expires", "-1");
        }
      },
    });
    // ....
}
AStafan 2020.03.12

我们在同一问题上苦苦挣扎,发现有些人的浏览器甚至不手动更新最新版本,甚至不会拉出最新版本。我们在各个层(包括用于托管文件的CDN)上进行缓存时都遇到了问题。

我们还努力维护版本,并在出现问题时能够快速重新部署以前的版本。

我们的解决方案(使用基于vue-cli Webpack的项目):

1)我们将发行版构建为具有版本特定的文件夹,而不是“静态”文件夹。这也有助于我们跟踪构建并在需要时“撤消”部署。要更改“静态”目录,请在index.js的“ build”下更改“ assetsSubDirectory”,然后将“ assetsPublicPath”更改为您的CDN路径。

2)我们使用Webpack Assets Manifest构建指向所有资产的manifest.json文件。我们的清单包含高安全性的应用程序,它包含所有文件的哈希。

3)我们将版本化的文件夹(包含js和css)上传到CDN。

4)(可选)我们在后端服务器上托管一个动态index.html文件。后端服务器使用从manifest.json上的数据中提取的模板系统来填充样式表和脚本的链接(请参阅#5)。这是可选的,因为您可以使用force-reload选项,如下面的注释所示,这不是很好的体验,但确实可以。

5)要发布新版本,我们将manifest.json发布到后端服务器。我们通过GraphQL端点执行此操作,但是您可以手动将json文件放在某个位置。我们将其存储在数据库中,并使用它来填充index.html,还使用它来使用文件哈希来验证文件(以验证我们的CDN未被黑客入侵)。

结果:立即更新,并具有轻松跟踪和更改版本的能力。我们发现它将立即在几乎所有用户的浏览器中提取新版本。

另一个好处是:我们正在构建一个要求高安全性的应用程序,并将index.html托管在我们(已安全的)后端上使我们能够更轻松地通过安全审核。


编辑2/17/19

我们发现,尽管没有缓存头,公司网络仍在进行代理缓存。IE 11似乎也忽略了缓存头。因此,某些用户没有获得最新版本。

我们有一个version.json在构建时递增/定义。版本号包含在manifest.json中。构建包将自动上传到S3。然后,我们将manifest.json传递给后端(我们在“管理”区域的条目页面上进行此操作)。然后,我们在该UI上设置“活动”版本。这使我们可以轻松地更改/还原版本。

后端将“ currentVersion”作为所有请求的响应标头。如果currentVersion!==版本(在version.json中定义),则我们要求用户单击以刷新其浏览器(而不是强制对其进行强制)。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android