Skip to content
项目

GreatAuk/plugin-web-update-notification

在 GitHub 查看

GreatAuk/plugin-web-update-notification has 662 GitHub stars and 62 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-15 13:57 UTC. Last push 2026-11-13.

这些数字如何统计

实测星标增长

24小时
0
7天
正在收集历史
15天
正在收集历史
1个月
正在收集历史

各周期内的星标净变化,周期相互重叠,并非每日新增。缺失的测量保持空白。星标代表关注度,不代表软件质量。

关于

Tiny lib, Detect webpage updates and notify user to reload. support Vite、Umijs、Rspack、Webpack、Nuxt.

网站与应用

README.zh-CN.md

原文

English | 简体中文

plugin-web-update-notification

Gzip Size NPM Version NPM Downloads License discussions-image

zread DeepWiki

检测已部署网页的版本变化,并提示用户刷新页面。支持 Vite、UmiJS、Webpack、Rspack 和 Nuxt。

构建时,插件将 Git 提交哈希、SVN 修订号、package.json 版本号、构建时间戳或自定义值写入版本文件。运行时,客户端获取服务器端版本,并与页面内置版本比较;版本不一致时,将提示用户刷新页面。

检测时机

插件会在下列时机请求 version.json:

  1. 首次加载页面时。
  2. 定时轮询时,默认间隔为 10 分钟。
  3. JavaScript 资源加载失败时,例如资源返回 404。
  4. 标签页 refocus or revisible。

查看更新提示

使用默认配置安装插件后,完成构建并部署。打开网页并保持该标签页处于打开状态,然后修改代码、重新构建并再次部署。在 Git 仓库中,默认的 versionType 为 git_commit_hash,因此需要提交新的 Git commit 才会产生新版本号。重新进入原标签页后,页面右下角会显示更新提示。

插件仅在生产构建中生效,开发模式不会注入更新检测逻辑。

工作原理

构建时(版本获取策略)

flowchart TD
    Start([插件启动: 构建阶段]) --> Detect[自动检测仓库类型<br/>查找 .git / .svn 目录]
    Detect --> Type{选择 versionType}

    Type -->|git_commit_hash| Git["git rev-parse --short HEAD"]
    Type -->|svn_revision_number| Svn["svnversion"]
    Type -->|pkg_version| Pkg["process.env.npm_package_version"]
    Type -->|build_timestamp| Ts["Date.now()"]
    Type -->|custom| Custom["customVersion 选项"]

    Git --> Check{是否获取成功}
    Svn --> Check
    Pkg --> Check
    Check -->|失败| Fallback[降级到 build_timestamp]
    Check -->|成功| Version[获得版本号]
    Ts --> Version
    Custom --> Version
    Fallback --> Version

    Version --> Emit[生成构建产物<br/>version.json / .js / .css<br/>带 MD5 前 8 位内容哈希]
    Emit --> Inject[注入标签与锚点]
    Inject --> End([构建完成])

运行时(检测时机与动作)

sequenceDiagram
    participant U as 用户/浏览器
    participant S as 注入脚本
    participant Srv as 服务器(version.json)

    Note over S: 内置 LOCAL_VERSION(打包时写入)

    rect rgb(235, 245, 255)
    Note over U,S: 触发检查的 4 种时机
    U->>S: 1. 首次加载页面(checkImmediately)
    U->>S: 2. 定时轮询(checkInterval,默认 10 分钟)
    U->>S: 3. JavaScript 资源加载失败(checkOnLoadFileError)
    U->>S: 4. 标签页重新获得焦点或变为可见(checkOnWindowFocus)
    end

    S->>Srv: fetch version.json
    Srv-->>S: { version, silence }

    alt 版本相同
        S-->>U: 不处理
    else 版本不同
        alt silence = true
            S-->>U: 静默,不提示
        else hiddenDefaultNotification = false
            S-->>U: 显示右下角更新通知
            U->>S: 点击「刷新」-> location.reload() / onClickRefresh
            U->>S: 点击「忽略」-> dismissUpdate()
        else hiddenDefaultNotification = true
            S-->>U: 派发 plugin_web_update_notice 事件<br/>(自定义通知/行为)
        end
    end

适用场景

用户可能长期不关闭网页。前端发布新版本后,旧页面仍可能引用已移除的资源,导致资源 404、页面异常或白屏。该插件可在检测到版本变化时提示用户刷新,以减少这类问题。

安装

**仅支持 ESM:**当前版本仅支持 ESM。如果你的项目仍依赖 CommonJS,请安装 1.8.1 版本。

# Vite
pnpm add @plugin-web-update-notification/vite -D

# UmiJS
pnpm add @plugin-web-update-notification/umijs -D

# Webpack 插件
pnpm add @plugin-web-update-notification/webpack -D

# Rspack 插件
pnpm add @plugin-web-update-notification/rspack -D

# Nuxt 模块
pnpm add @plugin-web-update-notification/nuxt -D

使用

Vite | UmiJS | Webpack | Rspack | Nuxt

禁用 index.html 缓存

请确保 index.html 不被缓存。否则用户刷新页面后仍可能加载旧的入口文件,导致更新提示持续出现。对于单页应用(SPA),这也是推荐的部署方式。

在 Nginx 中禁用缓存:

# nginx.conf
location / {
  index index.html index.htm;

  if ( $uri = '/index.html' ) { # 禁用 index.html 缓存
    add_header Cache-Control "no-cache, no-store, must-revalidate";
  }

  try_files $uri $uri/ /index.html;
}

也可以通过 HTML 的 meta 标签禁用缓存:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
    <meta http-equiv="Pragma" content="no-cache" />
    <meta http-equiv="Expires" content="0" />
  </head>
</html>

Vite

基础使用

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { webUpdateNotice } from '@plugin-web-update-notification/vite'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    webUpdateNotice({
      logVersion: true,
    }),
  ],
})

自定义通知文案

// vite.config.ts
export default defineConfig({
  plugins: [
    vue(),
    webUpdateNotice({
      notificationProps: {
        title: '标题',
        description: 'System update, please refresh the page',
        buttonText: '刷新',
        dismissButtonText: '忽略',
      },
    }),
  ],
})

国际化

// vite.config.ts
export default defineConfig({
  plugins: [
    vue(),
    webUpdateNotice({
      // 内置语言:zh_CN | zh_TW | en_US
      locale: 'en_US',
      localeData: {
        en_US: {
          title: '📢 system update',
          description: 'System update, please refresh the page',
          buttonText: 'refresh',
          dismissButtonText: 'dismiss',
        },
        zh_CN: {
          ...
        },
        ...
      },
    }),
  ],
})

// 在其他文件中切换语言
window.pluginWebUpdateNotice_.setLocale('zh_CN')

隐藏默认通知并自定义处理逻辑

// vite.config.ts
export default defineConfig({
  plugins: [
    vue(),
    webUpdateNotice({
      hiddenDefaultNotification: true,
    }),
  ],
})

// 在其他文件中监听自定义更新事件
document.body.addEventListener('plugin_web_update_notice', (e) => {
  const { version, options } = e.detail
  // 显示自定义通知,或执行其他业务逻辑。
  alert('System update!')
})

UmiJS

不支持 Umi 2。Umi 2 项目可尝试通过 chainWebpack 配置 Webpack 插件。

// .umirc.ts
import { defineConfig } from 'umi'

export default defineConfig({
  plugins: ['@plugin-web-update-notification/umijs'],
  webUpdateNotification: {
    versionType: 'git_commit_hash',
    logVersion: true,
    checkInterval: 0.5 * 60 * 1000,
    notificationProps: {
      title: 'system update',
      description: 'System update, please refresh the page',
      buttonText: 'refresh',
      dismissButtonText: 'dismiss',
    },
  },
})

defineConfig 中 webUpdateNotification 的类型来自 Umi 在 src/.umi 下生成的文件,注册插件后执行过 umi setup、umi dev 或 umi build 才有字段补全。Umi 生成的类型把所有函数类型的选项都写成 () => any,因此自定义 logVersion 时需将参数声明为可选才能通过类型检查,例如 logVersion: (version?: string, releaseTime?: number) => { ... }。

Webpack

插件只在生产构建时生效。mode 为 development,或以 watch 模式运行(包括 webpack-dev-server、vue-cli-service serve)时,插件不做任何处理,因为它需要改写写入磁盘的 index.html。未设置 mode 时,webpack 按 production 构建,插件正常生效。

// vue.config.js(vue-cli project)
const { WebUpdateNotificationPlugin } = require('@plugin-web-update-notification/webpack')
const { defineConfig } = require('@vue/cli-service')

module.exports = defineConfig({
  // ...other config
  configureWebpack: {
    plugins: [
      new WebUpdateNotificationPlugin({
        logVersion: true,
      }),
    ],
  },
})

Rspack

插件只在生产构建时生效。mode 为 development,或以 watch 模式运行(包括 rspack serve、rsbuild dev)时,插件不做任何处理,因为它需要改写写入磁盘的 index.html。未设置 mode 时,Rspack 按 production 构建,插件正常生效。

// rspack.config.js
const { HtmlRspackPlugin } = require('@rspack/core')
const { WebUpdateNotificationPlugin } = require('@plugin-web-update-notification/rspack')

module.exports = {
  plugins: [
    new HtmlRspackPlugin(),
    new WebUpdateNotificationPlugin({
      logVersion: true,
    }),
  ],
}

该插件也支持 Rsbuild:

// rsbuild.config.ts
import { defineConfig } from '@rsbuild/core'
import { WebUpdateNotificationPlugin } from '@plugin-web-update-notification/rspack'

export default defineConfig({
  tools: {
    rspack: {
      plugins: [
        new WebUpdateNotificationPlugin({
          logVersion: true,
        }),
      ],
    },
  },
})

Nuxt

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@plugin-web-update-notification/nuxt'],
  webUpdateNotification: {
    logVersion: true,
  },
})

支持 SSG(nuxt generate)、SPA(ssr: false)和 SSR(nuxt build)三种模式。该模块仅在生产构建时生效,开发模式下不会启用。

配置项

function webUpdateNotice(options?: Options): Plugin

export interface Options {
  /**
   * 版本号类型:'git_commit_hash' | 'svn_revision_number' | 'pkg_version' | 'build_timestamp' | 'custom'
   * - Git 仓库默认使用 'git_commit_hash'。
   * - SVN 仓库默认使用 'svn_revision_number'。
   * - 未识别的仓库默认使用 'build_timestamp'。
   * */
  versionType?: VersionType
  /**
   * 自定义版本号。versionType 为 'custom' 时必填。
   */
  customVersion?: string
  /** 轮询间隔,单位为 ms。
   * 设置为 0 时不轮询。
   * @default 10 * 60 * 1000
   */
  checkInterval?: number
  /**
   * 窗口重新获得焦点时检测更新。
   * @default true
   */
  checkOnWindowFocus?: boolean
  /**
   * 页面加载完成后立即检测更新。
   * @default true
   */
  checkImmediately?: boolean
  /**
   * JavaScript 文件加载失败时检测更新。
   * @default true
   */
  checkOnLoadFileError?: boolean
  /**
   * 是否在控制台输出版本号。
   *
   * 也可传入函数以自定义版本号的处理方式。函数接收版本号和发布时间(构建时由 `Date.now()` 得到的毫秒时间戳)。
   * ```ts
   * logVersion: (version, releaseTime) => {
   *   // 默认行为
   *   console.log(`version: %c${version}`, 'color: #1677ff')
   *   console.log(`release time: %c${new Date(releaseTime).toLocaleString()}`, 'color: #1677ff')
   * }
   * ```
   *
   * 注意:函数会在构建时通过 `fn.toString()` 序列化并原样写入注入脚本,因此必须自包含。
   * 它在浏览器中执行,不能引用构建配置里的闭包变量、import 或 Node.js API,只能使用浏览器全局对象。
   * 请使用箭头函数或 `function` 表达式(`logVersion(v) {}` 这类方法简写序列化后不是合法表达式)。
   * @default true
   */
  logVersion?: boolean | ((version: string, releaseTime: number) => void)
  /**
   * 是否静默更新通知。
   * 例如,当前版本为 v1.0 时,可为 v1.0.1 设置 true。用户升级到该版本时不会看到通知。
   */
  silence?: boolean
  /**
   * @deprecated
   */
  customNotificationHTML?: string
  /** notificationProps 的优先级高于 locale。 */
  notificationProps?: NotificationProps
  notificationConfig?: NotificationConfig
  /**
   * 内置语言:zh_CN | zh_TW | en_US
   * @default 'zh_CN'
   * */
  locale?: string
  /**
   * 自定义语言数据。
   * @link 默认数据:https://github.com/GreatAuk/plugin-web-update-notification/blob/main/packages/core/src/locale.ts
   */
  localeData?: LocaleData
  /**
   * 是否隐藏默认通知。设置为 true 后,需要自行处理更新事件。
   * ```ts
    document.body.addEventListener('plugin_web_update_notice', (e) => {
      const { version, options } = e.detail
      // 显示自定义通知,或执行其他业务逻辑。
      alert('System update!')
    })
   * ```
   * @default false
   */
  hiddenDefaultNotification?: boolean
  /**
   * 是否隐藏忽略按钮。
   * @default false
   */
  hiddenDismissButton?: boolean
  /**
   * 自 1.2.0 版本起,通常无需设置该项。插件会自动读取 Vite 的 base、Webpack 的 publicPath 或 Umi 的 publicPath。
   *
   * 注入文件的公共基础路径,可取:
   * - 绝对路径,如 /foo/。
   * - 完整 URL,如 https://foo.com/。
   * - 空字符串(默认值)或 ./(不推荐,见常见问题)。
   *
   * 路径末尾必须保留 /。
   */
  injectFileBase?: string
}

export type VersionType =
  | 'git_commit_hash'
  | 'svn_revision_number'
  | 'pkg_version'
  | 'build_timestamp'
  | 'custom'

export interface NotificationConfig {
  /**
   * 刷新按钮颜色。
   * @default '#1677ff'
   */
  primaryColor?: string
  /**
   * 忽略按钮颜色。
   * @default 'rgba(0,0,0,.25)'
   */
  secondaryColor?: string
  /** @default 'bottomRight' */
  placement?: 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'
}

export interface NotificationProps {
  title?: string
  description?: string
  /** 刷新按钮文案。 */
  buttonText?: string
  /** 忽略按钮文案。 */
  dismissButtonText?: string
}

export type LocaleData = Record<string, NotificationProps>

运行时方法

方法 参数 说明
window.pluginWebUpdateNotice_.setLocale locale:zh_CN、zh_TW 或 en_US 设置通知语言。
window.pluginWebUpdateNotice_.closeNotification — 关闭通知。
window.pluginWebUpdateNotice_.dismissUpdate — 忽略当前更新并关闭通知,行为与“忽略”按钮一致。
window.pluginWebUpdateNotice_.checkUpdate — 手动检测更新。该方法内置 5,000 ms 节流:执行一次检测后,5,000 ms 内的再次调用不会发起新请求。返回 Promise<{ updated, version }>。
interface Window {
  pluginWebUpdateNotice_: {
    /**
     * 设置通知语言。
     * 内置语言:zh_CN、zh_TW、en_US。
     */
    setLocale: (locale: string) => void
    /**
     * 手动检测更新。该方法内置 5,000 ms 节流:执行一次检测后,5,000 ms 内的再次调用不会发起新请求,并返回该次检测的结果。
     * 返回的 Promise 不会 reject,检测失败时 `updated` 为 `false`。
     */
    checkUpdate: () => Promise<{ updated: boolean; version: string }>
    /** 忽略当前更新并关闭通知,行为与“忽略”按钮一致。 */
    dismissUpdate: () => void
    /** 关闭通知。 */
    closeNotification: () => void
    /**
     * 刷新按钮点击事件。设置后会覆盖默认的 location.reload() 行为。
     */
    onClickRefresh?: (version: string) => void
    /**
     * 忽略按钮点击事件。设置后会覆盖默认的 dismissUpdate() 行为。
     */
    onClickDismiss?: (version: string) => void
  }
}

构建产物

构建完成后,插件会在输出目录生成版本文件、检测脚本和样式文件,并将它们注入 HTML。

inject_content

常见问题

  1. 如何获得 TypeScript 类型提示?

    如果需要调用 window.pluginWebUpdateNotice_,或监听自定义更新事件,请在项目中添加对应插件包的类型引用:

    // src/shim.d.ts
    
    // 使用 Vite 插件时
    /// <reference types="@plugin-web-update-notification/vite" />
    
    // 使用 Umi 插件时
    /// <reference types="@plugin-web-update-notification/umijs" />
    
    // 使用 Webpack 插件时
    /// <reference types="@plugin-web-update-notification/webpack" />
    
  2. 请求 version.json 时返回 404,如何处理?

    将构建产物部署到 CDN 时:

    // vite.config.ts
    
    const prod = process.env.NODE_ENV === 'production'
    
    const cdnServerUrl = 'https://foo.com/'
    
    export default defineConfig({
      base: prod ? cdnServerUrl : '/',
      plugins: [
        vue(),
        webUpdateNotice({
          injectFileBase: cdnServerUrl,
        }),
      ],
    })
    

    在非根目录下部署的项目:

    // vite.config.ts
    
    const prod = process.env.NODE_ENV === 'production'
    
    const base = '/folder/' // https://example.com/folder/
    
    export default defineConfig({
      base,
      plugins: [
        vue(),
        webUpdateNotice({
          injectFileBase: base,
        }),
      ],
    })
    

    自 1.2.0 版本起,通常无需设置 injectFileBase。插件会自动读取 Vite 的 base、Webpack 的 publicPath 或 Umi 的 publicPath。

    不推荐使用相对路径(如 base: './')。 注入脚本会基于自身 URL 解析相对路径,所以在 history 路由中跳转到嵌套路由后,版本检测仍能正常工作。但如果直接打开 /user/profile 这样的嵌套路由,浏览器会把 index.html 中 ./ 开头的脚本按 /user/ 解析,注入脚本和应用自身的资源都会返回 404。建议按实际部署位置使用绝对路径(如 '/' 或 '/folder/')。如必须使用相对路径,请改用 hash 路由,或在 index.html 中添加 <base href="/">。

  3. 如何自定义通知的“刷新”和“忽略”按钮事件?

    // 设置后会覆盖默认的 location.reload() 行为。
    window.pluginWebUpdateNotice_.onClickRefresh = (version) => {
      alert(`click refresh btn: ${version}`)
    }
    
    // 设置后会覆盖默认的 dismissUpdate() 行为。
    window.pluginWebUpdateNotice_.onClickDismiss = (version) => {
      alert(`click dismiss btn: ${version}`)
    }
    
  4. 如何自定义通知样式?

    可通过更高优先级的 CSS 覆盖默认样式。参见默认样式文件。

    默认样式通过 prefers-color-scheme 自动适配暗色模式,颜色由 .plugin-web-update-notice 上的 CSS 变量控制,可直接覆盖变量:

    .plugin-web-update-notice {
      --plugin-web-update-notice-bg: #fff;
      --plugin-web-update-notice-color: #000000d9;
      --plugin-web-update-notice-shadow: 0 6px 16px #00000014;
      --plugin-web-update-notice-btn-hover-bg: rgba(64, 87, 109, 0.1);
      --plugin-web-update-notice-refresh-color: #1677ff;
      --plugin-web-update-notice-dismiss-color: rgba(0, 0, 0, 0.25);
    }
    
    <!-- 通知 HTML 结构 -->
    
    <div class="plugin-web-update-notice-anchor">
      <div class="plugin-web-update-notice" role="alert" aria-live="polite">
        <div class="plugin-web-update-notice-content" data-cy="notification-content">
          <div class="plugin-web-update-notice-content-title">📢 system update</div>
          <div class="plugin-web-update-notice-content-desc">
            System update, please refresh the page
          </div>
          <div class="plugin-web-update-notice-tools">
            <button
              type="button"
              class="plugin-web-update-notice-btn plugin-web-update-notice-dismiss-btn"
            >
              dismiss
            </button>
            <button
              type="button"
              class="plugin-web-update-notice-btn plugin-web-update-notice-refresh-btn"
            >
              refresh
            </button>
          </div>
        </div>
      </div>
    </div>
    
  5. 如何手动检测更新?

    // 在每次 Vue Router 路由切换前检测更新
    router.beforeEach((to, from, next) => {
      window.pluginWebUpdateNotice_.checkUpdate()
      next()
    })
    
  6. 如何让某次更新不显示提示?

    例如,用户当前使用 v1.0,需要升级到 v1.0.1,但不希望显示更新提示:

    webUpdateNotice({
      ...
      silence: true
    })
    

相关文章

许可证

MIT