前端如何检测项目中新版本的发布?

前言

你是否也曾遇到过这种情况,每次发完版之后都还会有用户反馈问题没有被修复,一顿排查之后发现他用的还是旧的版本。

用户:在 XX 页面 XX 字段还是不展示
我:刷新下页面
用户:刷新了啊
我:强刷一下,Ctrl + F5

这一切都要归咎于 浏览器缓存,那么如何解决这一痛点呢?这篇文章将介绍如何检测版本变更并通知用户刷新页面。

实现思路

  1. 在项目构建(build)的时候,生成一个 version.json 版本信息文件,路径:dist/version.json
  2. 在切换路由的时候去请求服务器的 version.json 文件与本地缓存的版本信息做一个对比

准备工作

本文使用的是 Angular 技术栈,但是本质上还是使用的 webpack 去构建,所以万变不离其宗!

  • angular | v17
  • @angular-builders/custom-webpack | v17

开始

一、Angular 自定义 Webpack 配置

1.1 安装 @angular-builders/custom-webpack

npm install @angular-builders/custom-webpack -D

1.2 使用自定义配置运行开发服务器:@angular-devkit/build-angular -> @angular-builders/custom-webpack

"architect": {
  ...
  "build": {
    "builder": "@angular-builders/custom-webpack:browser",
    "options": {
      "customWebpackConfig": {
        "path": "./extra-webpack.config.ts"
      },
      ...
    }
  },
  "serve": {
    "builder": "@angular-builders/custom-webpack:dev-server",
    "options": {
      "browserTarget": "my-project:build"
    }
  }
  ...
}

1.3 配置 extra-webpack.config.ts

import * as webpack from "webpack";

export default (config: webpack.Configuration) => {
  config.plugins = [
    ...config.plugins,
    // 这里配置插件
  ];
  return config;
};

二、自定义版本信息插件

2.1 创建插件 version-plugin.js,参考文档 creating-a-plugin

const fs = require("fs");
const path = require("path");

class VersionPlugin {
  constructor({ version }) {
    this.version = version;
  }
  apply(compiler) {
    compiler.hooks.done.tap("VersionPlugin", (stats) => {
      const versionInfo = {
        version: this.version,
        buildTime: new Date().toISOString(),
      };
      const outputPath = stats.compilation.options.output.path;
      const versionFilePath = path.resolve(outputPath, "version.json");
      fs.writeFileSync(versionFilePath, JSON.stringify(versionInfo, null, 2));
      console.log("Version file generated successfully!");
    });
  }
}
module.exports = VersionPlugin;

2.2 在 extra-webpack.config.ts 中使用 VersionPlugin 插件

import * as webpack from "webpack";
import * as VersionPlugin from "./version-plugin.js";

export default (config: webpack.Configuration) => {
  const version = new Date().getTime();
  config.plugins = [
    ...config.plugins,
    // 将版本号写入全局变量
    new webpack.DefinePlugin({
      "process.env.VERSION": JSON.stringify(version),
    }),
    // 创建 version.json 放入 dist 目录
    new VersionPlugin({ version: version }),
  ];
  return config;
};

运行 npm run build 检测 version.json 文件是否写入成功!

三、检测变更并通知

我这里选择的是在用户切换路由的时候去检测,当然也可以选择其它的时机,例如开一个定时器,等。

3.1 在 app.component.ts 中去监听路由变化

import { Router, NavigationStart } from "@angular/router";

export class AppComponent {
  constructor(private router: Router) {
    this.onRouterChange();
  }

  onRouterChange(): void {
    this.router.events.subscribe((event) => {
      if (event instanceof NavigationStart) {
        this.checkVersion();
      }
    });
  }
}

3.2 实现检测版本的方法,请求远程服务器的 version.json 版本信息与项目中的全局变量 process.env.VERSION 做对比

checkVersion(): void {
  if (!environment.production) {
    return;
  }
  fetch('./version.json')
    .then(response => response.json())
    .then(versionInfo => {
      if (versionInfo.version !== process.env.VERSION) {
        // TODO: 弹窗提示 或 直接刷新
        this.refresh();
      }
    })
    .catch(error => {
      console.error(error);
    });
}

refresh(): void {
  window.location.reload(true);
}

done!

结语

看到这里,希望能够给你提供一点思路,方法有很多种,也欢迎一起交流讨论!