前端项目部署,想要自动检测更新后通知用户刷新页面,但是发版后main.js入口文件不调用为什么?

想实现,"前端项目部署自动检测更新后通知用户刷新页面".但是发版后,main.js入口文件并不再次执行是为什么?
在main.js引入了version版本比较,但是发版之后,浏览器页面并不会自动再次执行main.js,导致用户如果之前一直在老页面,即便我发版,他也更新不到.

我是用oss发版的,文件名字hash我也做了处理,但是为什么引用文件名字都变了,浏览器还是老页面吗呢,不去读最新的资源文件这是老页面 引用的js文件这是新页面加了hash的文件名
但是项目页面如果不刷新(下图是老页面读的),一直停留在老页面,他就一直访问老页面js,导致我的版本更新代码他读不到
项目老页面引用的
这种我要怎么处理

阅读 2.3k
avatarAI BotBETA

你遇到的问题是因为浏览器缓存了旧的 JavaScript 文件。当你的前端项目部署后,新的 JavaScript 文件已经被生成并放在了服务器上,但是因为浏览器的缓存,用户可能仍然会加载旧的、缓存的版本。

要解决这个问题,你可以采取以下几种方法:

  1. 使用版本号或查询参数: 在 JavaScript 文件的 URL 中添加一个版本号或查询参数(例如,main.js?v=1.0.0),这样每次更改版本时,URL 都会变化,导致浏览器认为这是一个新的文件并重新下载。
  2. 强制刷新: 在你的通知用户刷新页面中,可以加入一个强制刷新操作。例如,你可以在通知中提供一个链接,链接的 URL 中加入了一个随机数或时间戳,这样每次点击链接时,URL 都会变化,从而触发浏览器重新加载页面。
  3. 使用 Service Worker: Service Worker 可以拦截网络请求,并在本地缓存文件。你可以编写一个 Service Worker,让它检测文件是否更新,如果文件已更新,则强制加载新文件。
  4. 使用 OSS 的缓存控制策略: 如果你使用的是 OSS(一种对象存储服务),你可以设置文件的 HTTP 缓存控制头,例如 Cache-ControlExpires,来控制浏览器如何缓存文件。例如,你可以设置一个较短的有效期,这样浏览器就不会长时间缓存文件。

这些方法中的每一种都有其优缺点,你需要根据你的具体情况选择最适合的方法。

3 个回答

在掘金看到的监测页面更新的方法,使用了new Worker,直接去请求页面获取etag、last-modified,判断和之前的是否相等,实测可用,定时器时间可以自定。

  try {
        const worker = new Worker(new URL('./utils/autoUpdate.ts', import.meta.url), {
            type: 'module',
        });

        worker.postMessage({
            url: `${window.location.protocol}//${window.location.host}`,
        });

        worker.onmessage = (e) => {
            if (e.data === 1) {
                ElMessageBox.alert('页面已更新,点击刷新页面', {
                    confirmButtonText: '刷新',
                    showClose: false,
                    callback: (action: any) => {
                        window.location.reload();
                    },
                });
            }
        };

        worker.onerror = (err) => {
            console.error('->>>err', err);
        };
    } catch (Err) {
        console.error('11111->>>err', Err);
    }

utils/autoUpdate.ts

export let previousTimeTag: string | null; // 时间戳,响应头中的tag和last-modified字段之一
let url: string; // 请求的url
let intervalTimer: number; // 轮询的定时器
// 获取当前最新时间戳
async function getTimeTag() {
    const res = await fetch(url, {
        method: 'HEAD',
        cache: 'no-cache',
    });
    return res.headers.get('etag') || res.headers.get('last-modified');
}

// 判断Tag是否发生变化
async function juede() {
    const currentTimeTag: string | null = await getTimeTag();
    console.log('currentTimeTag--> ' + currentTimeTag, ' ________ ' + 'previousTimeTag--> ' + previousTimeTag);

    if (currentTimeTag !== previousTimeTag) {
        intervalTimer && clearInterval(intervalTimer);
        self.postMessage(1);
    }
}

self.onmessage = function (e): void {
    const data = e.data;
    if ('url' in data) {
        try {
            url = data['url'];
            (async function () {
                // 通过立即执行函数,记录首次请求的时间戳,以便与后面轮询得出的时间戳进行对比
                previousTimeTag = await getTimeTag();
                intervalTimer && clearInterval(intervalTimer);
                // 执行轮询juede函数
                intervalTimer = setInterval(juede, 60 * 1000 * 5);
            })();
        } catch (err) {
            console.log('Worker got unknown message:111' + err);
        }
    } else {
        console.log('Worker got unknown message:' + data);
    }
};

轮询。
最近某视频网站恰巧有人做过演示,去搜搜看看。

推荐一个插件 @plugin-web-update-notification,可以在前端项目打包后,提示用户刷新页面。

以 git commit hash (也支持 svn revision number、package.json version、build timestamp、custom) 为版本号,打包时将版本号写入 json 文件。客户端轮询服务器上的版本号(浏览器窗口的 visibilitychange、focus 事件辅助),和本地作比较,如果不相同则通知用户刷新页面。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题