根本原因是微信等内置浏览器强缓存index.html导致加载旧js,必须通过构建时文件名哈希(如app.[contenthash:8].js)、index.html哈希化(html-webpack-plugin配置)、nginx强制禁用html缓存、pwa配置clientsclaim/skipwaiting,并配合微信/钉钉离线包平台发布。

uni-app H5端在移动端(尤其是微信内置浏览器、钉钉、企业微信等)加载旧代码,根本不是“清不清缓存”的问题,而是浏览器把整个静态资源(index.html、app.js、chunk-vendors.js)都缓存住了,连 HTML 都没重新拉——你改了代码,用户打开的还是上次缓存下来的 index.html,自然加载的全是旧 JS。
webpack 打包时给文件名加哈希或时间戳
这是最直接有效的手段。只靠修改 URL 参数或 Cache-Control 响应头,在很多国产安卓 WebView 里根本不起作用,因为它们会无视这些头,硬缓存 HTML 和 JS 文件。
-
vue.config.js中配置output.filename和output.chunkFilename,强制让每次构建产出的 JS/CSS 文件名不同,例如:app.20260619123456.js或app.[contenthash:8].js - 必须同时处理
index.html:默认它不带哈希,会被长期缓存。需用html-webpack-plugin插件配置filename: 'index.[contenthash:6].html',并确保服务器能正确返回该文件(Nginx 需配try_files $uri /index.[hash].html;或统一 fallback 到最新版) - 注意:如果用了 PWA,
workbox会接管资源缓存,此时光改文件名不够,还得在vue.config.js的 PWA 配置中设clientsClaim: true和skipWaiting: true,否则新 Service Worker 不会立即激活
nginx 配置必须禁用 HTML 缓存
哪怕文件名带哈希,如果 index.html 本身被缓存 1 小时,用户首次访问仍会拿到旧 HTML,进而加载一堆旧 JS 资源。
- Nginx location 块中必须显式关闭 HTML 缓存:
location = /index.html { add_header Cache-Control "no-cache, no-store, must-revalidate"; add_header Pragma "no-cache"; add_header Expires "0"; } - 不要对所有路径都加
no-cache,JS/CSS 文件名带哈希后可以放心设长缓存(如max-age=31536000),提升二次访问性能 - 某些厂商定制 ROM(如华为 EMUI 内置浏览器)会忽略响应头,这时只能靠文件名哈希兜底
H5 端手动清理 localStorage/sessionStorage 是伪需求
uni.clearStorage() 只清自己写入的 key,而项目里大量存在 localStorage.setItem('ab_test_group', 'v2')、sessionStorage.setItem('draft', ...) 这类直写调用——它们不会被自动清理,但和“加载旧代码”完全无关。
- 这类存储清理是业务逻辑层面的事,比如登出时清除埋点 ID、AB 分组、草稿等,跟资源更新无因果关系
- 上线前用
grep -r "localStorage\.setItem\|sessionStorage\.setItem" src/检查所有直写点,补上对应removeItem或clear,别指望uni.clearStorage()代劳 - Service Worker 的
caches更是独立体系,uniAPI 完全无感,要清必须自己调caches.keys().then(keys => Promise.all(keys.map(k => caches.delete(k))))
微信/钉钉等环境要额外防“离线包”机制
微信浏览器(X5 内核)、钉钉内置 WebView 会自动启用“离线包”策略:首次加载成功后,后续即使网络正常,也可能优先从本地离线缓存取资源,且不校验版本。
- 解决方案不是前端能单方面解决的,需配合平台方配置:微信侧走「微信小程序·H5 离线包」后台提交新版本并发布;钉钉侧需在「钉钉开发者后台→H5 微应用→版本管理」中更新离线包 URL 并发布
- 开发阶段可临时在 URL 后加参数(如
?v=20260619)绕过离线包,但上线后必须走平台规范流程 - 这类机制下,连
index.html哈希和 Nginx 头都无效,前端唯一可控的是确保离线包地址本身带版本号(如https://a.com/h5/v2.3.0/index.html)
真正卡住上线效果的,往往不是某段 JS 没刷新,而是 index.html 没更新、离线包没发布、或者 PWA 的 Service Worker 没跳过等待。这三个地方漏掉一个,用户看到的就永远是旧世界。











