请问线上 web 项目如何自动更新?

2022-11-27 21:12:24 +08:00
 karott7
比如用户正在访问我的项目,然后我发布代码更新版本,想知道如何在用户不点击刷新或者不重开网页的情况下让用户获取最新版本代码?
4938 次点击
所在节点    程序员
54 条回复
opengps
2022-11-28 01:05:16 +08:00
你这个更新达到了无感体验实时级别,要求过于高了,现在的更新都是下次访问刷新
opengps
2022-11-28 01:06:41 +08:00
浏览器端通信,或者使用 websocket 做实时,或者使用高频轮训方式来更接近实时
neoblackcap
2022-11-28 01:09:13 +08:00
@karott7 如果要达到你的需求,仅仅是不需要人工介入,定时轮询加重载页面可能是最简单的。
能做到热更新当然好,但是没有一点思路,硬上热更新,很可能把握不住,做出来 bug 满天飞。
neoblackcap
2022-11-28 01:12:48 +08:00
@opengps 本质上就是网络监听,远程注入运行,JIT 热更新。说实在的,我看了一下帖子,没看出项目有这些必要。耗费人力成本太高,效果也不见得比轮询刷新强多少
lower
2022-11-28 08:19:39 +08:00
浏览器上实在不好处理的话,就用 electron 之类的搞个客户端壳子,在壳子里实现一些特定的外围功能……
296727
2022-11-28 09:06:41 +08:00
每个 http 请求的返回都加一个版本号,和当前的版本号不一样了,就强制刷新一下不就 OK 了?
0xcaffebabe
2022-11-28 09:29:10 +08:00
做过一个类似的需求,不过是用户切换窗口的时候检查一下有没有新版本,主要是比对打包 js 文件的哈希来实现
karott7
2022-11-28 10:06:39 +08:00
@neoblackcap @opengps @dcsuibian @ryougifujino

我觉得大家都把这个功能实现想复杂了,不必用 websocket ,也不搞热更新,也不用其他同事配合,只要前端一个人能就能完成。帖子开头和 #7 楼也把前提说清楚了,这个方案是针对 to b 的,比如自动售货机,肯定有一段空闲时用户不在使用的。
其实有些人已经说到点子上了,自动更新版本肯定得用 js 执行 location.reload(),肯定得增加版本号(但这个版本号不用是 x.y.z 的形式,应为要额外为版本判断写代码);

我昨晚也实验了一下,因为我目前就在做自动收银机的项目,大家看看这个方案咋样:
-- 给 index.html 文件设置 http 缓存响应头 no-store 或者 no-cache ,保证每次拿到的 index.html 文件都是最新的
-- 给 js/css/img 等其他资源设置一个比较长时间的缓存响应头,比如一年。
-- 每次打包都给 index.html 文件中的 html 元素增加当前打包的时间戳,打包后的 <html /> 元素就变成了 <html data-timestamp="..." />, 这个时间戳其实就是版本号,因为我们只需要探测最新版本
-- 我在全局增加一个每隔几分钟获取 index.html 的请求,fetch('/').then(response => const bodyString = response.text()), 拿到 document 字符串,再用正则解析出 data-timestamp 去和 document.documentElement.dataset.timestamp 对比,如果比这个值大,就是最新版代码,然后再检测用户没操作多少秒执行 location.reload(), 这样就更新代码了

再说下 location.reload() 的执行前怎么才能不破坏用户体验
- 如果是自动售卖机,我会给个 3 秒倒计时的弹窗,有文案提示系统检测到版本更新,即将更新,倒计时结束后就 reload
- 如果是后台管理,我会像 vscode 每次更新一样,右下角给个提示,让用户自己觉得是否更新

这个方案我昨天以为能最小代价更新代码,比如我只更新了一个 js 文件,我就希望刷新后除了这个 js 文件其他文件都能走缓存;其实不是,因为打包工具(比如 rollup )不止会给该 js 更新 hash ,所有引入该 js 文件的文件名中的 hash 都会改变,这就导致该 js 的祖先文件都不能走缓存了,现在服务器都是按请求收费的,这样肯定不划算,但目前没办法。

不过如果你把外部库( node_modules )都单独分割出来,这个 js 文件(一般称为 vendor )基本是不变的,所以我觉得即使是在弱网环境下,reload 也不会太慢。

不知道大家咋看?
karott7
2022-11-28 10:07:44 +08:00
@opengps 我没有要求无感体验哦
opengps
2022-11-28 10:34:28 +08:00
@karott7 不点击刷新或者不重开网页的情况下,这句话的要求,已经高于热更新重新刷新生效了
karott7
2022-11-28 10:44:05 +08:00
@opengps '想知道如何在用户不点击刷新或者不重开网页的情况下让用户获取最新版本代码?'
有前提,在用户不点击刷新,‘用户’
heishu
2022-11-28 10:58:55 +08:00
@karott7 #10 可不可以,你在 token 里面读取 package 的 version 加上,后端每次 token 验证 version 是不是最新的。这种的话前端要更新版本,后端存的 version 也要手动改新的版本号
karott7
2022-11-28 11:17:08 +08:00
@heishu 抱歉,#10 的话我说错了,不是‘请求’,是请问;
我觉得不用后端参与,越少人参与越好
menglizhi2333
2022-11-28 12:05:56 +08:00
PWA 可以做到无后端参与,进行 web 更新,你需要的文件缓存规则可以在 Service Work 中进行细致化定义

https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API/Using_Service_Workers#%E6%9B%B4%E6%96%B0%E4%BD%A0%E7%9A%84_service_worker
blankmiss
2022-11-28 12:46:28 +08:00
我说的灰度部署 是以我后端的角度去看这个问题的 前端只更新几个文件的 我想应该能够以#15 的方式进行
karott7
2022-11-28 13:09:24 +08:00
@blankmiss 我不懂灰度部署,不过#15 的方案中对比以文件内容生成 hash 值其实更好一点,线上项目也可能遇到回滚。
还有一种方式,fetch('/') 拿到 http etag 响应头,这也是个 hash 值,服务器自动生成,直接对比这个就好了
karott7
2022-11-28 13:10:37 +08:00
@menglizhi2333 我觉得没必要做成 PWA ,按照 #28 的方案,我觉得已经可以完成这个功能了,虽然有点瑕疵,但是对于 js 体积不大的项目来说已经完全够用了
coderyyj
2022-11-28 13:31:50 +08:00
我之前也有过这个需求,被我砍掉了
GreatAuk
2022-11-28 13:44:57 +08:00
whatFoxSay
2022-11-28 13:52:20 +08:00
gitaction

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/898339

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX