我有一个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>
有没有办法强制它每次加载新代码或(理想情况下)检查旧文件是否从服务器中消失,然后刷新浏览器?
答案 0 :(得分:7)
我们在同样的问题上苦苦挣扎,发现有些人的浏览器甚至不会提取最新版本,除非他们手动刷新。我们在各个层面都有缓存问题,包括我们托管文件的CDN。
我们还努力维护版本,并且如果出现问题,我们可以快速重新部署以前的版本。
我们的解决方案(使用基于vue-cli Webpack的项目):
1)我们将发行版构建为具有特定于版本的文件夹,而不是“静态”文件夹。这也有助于我们跟踪构建和撤消&#39;如果需要,部署。要改变静态&#39;目录,更改&quot; assetsSubDirectory&#39;在&#39; build&#39;在index.js中更改资产公共路径&#39;到您的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传递给后端(我们在Admin区域的入口页面上执行此操作)。然后我们设置&#34; active&#34;该UI上的版本。这使我们可以轻松更改/恢复版本。
后端将&#34; currentVersion&#34;作为所有请求的响应标头。如果currentVersion!== version(在version.json中定义),那么我们要求用户点击刷新他们的浏览器(而不是强制它们)。
答案 1 :(得分:5)
毫无疑问,这个问题很烦人。必须使用在标头中发送的自定义前端版本终结点来解决它。我正在使用Rails后端和Vue + Axios作为前端。请注意,我不需要服务人员,因此不使用任何服务人员。
基本上,只要有get请求并且应用程序的版本已更改(服务器可以告知相同信息),我就在重新加载
axiosConfig.js
axios.interceptors.response.use(
(resp) => {
const fe_version = resp.headers['fe-version'] || 'default'
if(fe_version !== localStorage.getItem('fe-version') && resp.config.method == 'get'){
localStorage.setItem('fe-version', fe_version)
window.location.reload() // For new version, simply reload on any get
}
return Promise.resolve(resp)
},
)
跟踪后端
application_controller.rb
after_action :set_version_header
def set_version_header
response.set_header('fe-version', Setting.key_values['fe-version'] || 'default')
end
application.rb
(CORS配置假定Vue在端口8080上运行)
config.middleware.insert_before 0, Rack::Cors do
allow do
origins ['localhost:8080', '127.0.0.1:8080']
resource '*', expose: ['fe-version'], headers: :any, methods: [:get, :post, :delete, :patch], credentials: true
end
end if Rails.env.development?
在此处撰写详细的文章:https://blog.francium.tech/vue-js-cache-not-getting-cleared-in-production-on-deploy-656fcc5a85fe
答案 2 :(得分:1)
基于this comprehensive answer on cache headers,如果可以控制,最好的选择是在服务器端解决此问题,因为<meta>
标记中的任何内容都将被服务器设置的标头覆盖
对该问题的评论表明您正在通过nginx服务此应用程序。使用上面的链接的答案,我能够通过以下方式在我的Nginx配置中为所有以Cache-Control
结尾的文件请求设置Expires
,Pragma
和.html
标头: / p>
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)。
答案 3 :(得分:1)
要删除缓存,您可以运行rm -rf node_modules/.cache
这将删除您的缓存。您可以在部署之前运行新版本。
我在运行生产版本时遇到了同样的问题,但是即使在本地运行时,我的代码也将指向生产版本,而不是我的最新更改。
我认为这是一个相关问题:https://github.com/vuejs/vue-cli/issues/2450
答案 4 :(得分:1)
我与一个轻巧的Express应用程序一起提供Nuxt应用程序,该应用程序处理服务器端身份验证和其他功能。我的解决方案是让Express在用户登录时将当前git哈希存储在cookie中。然后将该值与当前时间(以及有关当前用户的其他信息)一起放入Vuex存储中。
在更改路线时,路由器中间件检查距我们上次将商店的哈希值与实际哈希值进行比较以来已有多长时间了。如果超过一分钟,我们会向Express请求当前的哈希值,如果该值已更改,则将强制为当前路由进行服务器端渲染。
以下是相关代码:
server / index.js
const getRevision = function() {
return require('child_process')
.execSync('git rev-parse --short HEAD')
.toString()
.trim()
}
app.get(
'/login',
async function(req, res, next) {
// (log in the user)
const revision = getRevision()
res.cookie('x-revision', revision)
return res.redirect('/')
}
)
app.get(
'/revision',
function(req, res) {
const revision = getRevision()
return res.send(revision)
}
)
store / index.js
export const actions = {
nuxtServerInit({ dispatch }) {
const revisionHash = this.$cookies.get('x-revision')
dispatch('auth/storeRevision', revisionHash)
}
}
商店/auth.js
export const state = () => ({
revision: { hash: null, checkedAt: null }
})
export const mutations = {
setRevision(store, hash) {
store.revision = { hash: hash, checkedAt: Date.now() }
}
}
export const actions = {
storeRevision({ commit }, revisionHash) {
commit('setRevision', revisionHash)
},
touchRevision({ commit, state }) {
commit('setRevision', state.revision.hash)
}
}
中间件/checkRevision.js
export default async function({ store, route, app, redirect }) {
const currentRevision = store.state.auth.revision
const revisionAge = Date.now() - currentRevision.checkedAt
if (revisionAge > 1000 * 60) {
// more than a minute old
const revisionHash = await app.$axios.$get(
`${process.env.baseUrl}/revision`
)
if (revisionHash === currentRevision.hash) {
// no update available, so bump checkedAt to now
store.dispatch('auth/touchRevision')
} else {
// need to render server-side to get update
return redirect(`${process.env.baseUrl}/${route.fullPath}`)
}
}
return undefined
}
答案 5 :(得分:0)
如果您使用asp.net core,则可以在webpack中尝试以下技巧,该webpack生成js文件,其名称末尾带有哈希值。 dbContext
。
因此,您的index.html包含:
my-home-page-vue.30f62910.js
,这意味着您每次更改<link href=/js/my-home-page-vue.30f62910.js rel=prefetch>
都会在文件名中生成一个新的哈希值。
您唯一需要做的就是为index.html添加缓存限制
在您的Startup.cs中:
my-home-page.vue