Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] 发版后,页面不刷新会报错,希望能监听这种异常,方便提示用户刷新页面 #10171

Closed
junegod opened this issue Dec 29, 2022 · 12 comments

Comments

@junegod
Copy link

junegod commented Dec 29, 2022

image

Background

A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Proposal

Describe the solution you'd like, better to provide some pseudo code.

Additional context

Add any other context or screenshots about the feature request here.

@leftstick
Copy link
Contributor

这个需求单纯在前端代码层考虑的话,还是不太现实或者说实现过于困难了。无论如何都要涉及一定的部署工作

提供几个我这边的思路:

方法一

后端

增加一个 websocket 实现 或者一个长连接的 api,用来做“server-side-push”,即:服务器端发生变化时主动通知客户端。

那么,我就可以让后端在每次有新发布时,通知客户端有“new release”,前端可以自行决定是给用户一个 popup 还是 message,甚至直接帮用户刷新页面都行

前端

应用启动时,就通过 websocket 或者长连接和服务器建立通信渠道,虽然等待后端的消息,一旦发现有“new release”,我这边的做法是给用户一个popup,告诉他务必刷新页面,否则程序可能出现错误。

从解决方案的角度看,这是个很简单并且容易实现的东西,因为前后端要做的事情都很常规,并没有什么特殊技术要求。大致就是后端写个 api,前端写个监听器 这类的东西。

方法二

抛开后端,只在前端做。
那就是每次上线编译时,把所有生成的文件列表写到一个 文件里去,随便什么名字都行,譬如:output-meta.json。文件放到public目录下,随其他生成的文件一起部署。

前端代码里,写段请求监听程序, 应用启动时,每隔 1 小时(时间随便自己定)请求一次 output-meta.json,检查这个文件的内容是否有变化,有变化就提示用户,有新 release。请他刷新。

注意:output-meta.json 文件部署时必须配置成无缓存,不然前端每次请求的都是之前的 cache 的结果,那么检查内容变化也就无从谈起了

@junegod
Copy link
Author

junegod commented Dec 29, 2022

这个需求单纯在前端代码层考虑的话,还是不太现实或者说实现过于困难了。无论如何都要涉及一定的部署工作

提供几个我这边的思路:

方法一

后端

增加一个 websocket 实现 或者一个长连接的 api,用来做“server-side-push”,即:服务器端发生变化时主动通知客户端。

那么,我就可以让后端在每次有新发布时,通知客户端有“new release”,前端可以自行决定是给用户一个 popup 还是 message,甚至直接帮用户刷新页面都行

前端

应用启动时,就通过 websocket 或者长连接和服务器建立通信渠道,虽然等待后端的消息,一旦发现有“new release”,我这边的做法是给用户一个popup,告诉他务必刷新页面,否则程序可能出现错误。

从解决方案的角度看,这是个很简单并且容易实现的东西,因为前后端要做的事情都很常规,并没有什么特殊技术要求。大致就是后端写个 api,前端写个监听器 这类的东西。

方法二

抛开后端,只在前端做。 那就是每次上线编译时,把所有生成的文件列表写到一个 文件里去,随便什么名字都行,譬如:output-meta.json。文件放到public目录下,随其他生成的文件一起部署。

前端代码里,写段请求监听程序, 应用启动时,每隔 1 小时(时间随便自己定)请求一次 output-meta.json,检查这个文件的内容是否有变化,有变化就提示用户,有新 release。请他刷新。

注意:output-meta.json 文件部署时必须配置成无缓存,不然前端每次请求的都是之前的 cache 的结果,那么检查内容变化也就无从谈起了

方法一,每次发完版还得去维护的地方发布个消息或版本,对于小项目来说,太复杂繁琐了。
方法二其实和方法一差不多,每次得手动一下。
这都代码报错了,umi肯定知道啊,提示都是他报的。
我在vue项目里实现了window.addEventListener('error', handleError, true) 实现了

@leftstick
Copy link
Contributor

leftstick commented Dec 29, 2022

上面两个方案完全可以做到自动, 至少我这边在部署时是不需要人工额外做事情的。 还是那句话,没有任何特殊技术要求。

“这都代码报错了,umi肯定知道啊,提示都是他报的。”
都是静态文件请求,你的handleError 里是通过什么来识别 当前错误是 因为版本升级导致的?

因为从报错的信息来说, 程序错误, 网络请求错误,版本升级 都可能引发 “unexpected token” 类型的 error。

如果在前端能细化,直接区分出这种错误,那我觉得倒是很不错。可以单方面搞定确实要比 再拉几个其他人合作要更有效率

@junegod
Copy link
Author

junegod commented Dec 30, 2022

上面两个方案完全可以做到自动, 至少我这边在部署时是不需要人工额外做事情的。 还是那句话,没有任何特殊技术要求。

“这都代码报错了,umi肯定知道啊,提示都是他报的。” 都是静态文件请求,你的handleError 里是通过什么来识别 当前错误是 因为版本升级导致的?

因为从报错的信息来说, 程序错误, 网络请求错误,版本升级 都可能引发 “unexpected token” 类型的 error。

如果在前端能细化,直接区分出这种错误,那我觉得倒是很不错。可以单方面搞定确实要比 再拉几个其他人合作要更有效率

判断是js文件网络请求错误就行啊,咋不能区分,这种报错本身代码是不会有这问题的

@junegod
Copy link
Author

junegod commented Dec 30, 2022

目前根据报错信息,大概写了个能用的版本,
image
umi不会直接报404,不存在的js返回的是html
image

**
 * 判断js资源是否返回404状态码
 * @param url
 * @return {Promise<any>}
 */
function isScript404(url: string) {
  return new Promise((resolve) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, false);
    xhr.onreadystatechange = function () {
      if (xhr.readyState === XMLHttpRequest.DONE && xhr.status !== 200) {
        resolve(true);
        return;
      }
      const responseText = xhr.responseText;
      if (!responseText) {
        resolve(true);
        return;
      }
      // 内容不是"use strict 开头
      if (!responseText.startsWith('"use strict')) {
        resolve(true);
        return;
      }
      resolve(false);
    };
    xhr.send();
  });
}

/**
 * 处理错误函数
 * @param e
 */
async function handleError(e: any) {
  console.log('script resource load error....', e);
  const filename = e.filename;
  if (!filename) {
    return;
  }
  const fileExtName = getFileExtName(filename);
  if (!fileExtName || 'js' !== fileExtName) {
    return;
  }
  const bool = await isScript404(filename);
  if (!bool) {
    return;
  }
  alert('版本已更新,页面将自动刷新');
  window.location.reload();
}

// 绑定事件
window.addEventListener('error', handleError, true);

@q269384828
Copy link

两种方法, 一种是在错误阶段捕获, 一种是路由切换前判断一下. 所谓判断,就是判断一下 index.html 里面的umi的hash一致不一致.

@fz6m
Copy link
Member

fz6m commented Jan 31, 2023

特定的业务逻辑自行根据需求实现就行,不属于框架的职责。

如需通用化该能力,可以写成 umi 插件,调用 modifyHTML 在 html 里插入错误捕获刷新页面 reload 逻辑,先关闭了。

@fz6m fz6m closed this as completed Jan 31, 2023
@zhangxinyong12
Copy link

zhangxinyong12 commented Mar 8, 2023

818a88d7c5be096e7bf63e4bbc5f0f8

05030ba406728cff6ef082fb9e8074d

我目前的做法是开启hash。打包完成后写个时间戳作为版本号,再适当的时机请求接口数据,判断是否更新。nginx不缓存html

@junegod
Copy link
Author

junegod commented Mar 8, 2023

818a88d7c5be096e7bf63e4bbc5f0f8 05030ba406728cff6ef082fb9e8074d 05030ba406728cff6ef082fb9e8074d

我目前的做法是开启hash。打包完成后写个时间戳作为版本号,再适当的时机请求接口数据,判断是否更新。nginx不缓存html

你这个牛逼,就是要这效果

@zhangxinyong12
Copy link

d0dd88c812bc124ee29b4383ef1f092

@junegod
Copy link
Author

junegod commented Mar 9, 2023

d0dd88c812bc124ee29b4383ef1f092

方便的话都发个文字版,哈哈哈哈

@fz6m
Copy link
Member

fz6m commented Nov 30, 2023

umi 4 发版/异步块加载失败重试方法 ( #11920

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants