npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@plugin-web-update-notification/umijs

v1.7.1

Published

Umi plugin for detect web page updates and notify.

Downloads

108

Readme

English | 简体中文

plugin-web-update-notification

Detect webpage updates and notify user to reload. support vite, umijs and webpack.

Take the git commit hash (also support svn revision number、package.json version、build timestamp、custom) as the version number, and write version into json file. The client polls the version of the server (visibilitychange or focus event assistant), compares it with the local one, and if it is not the same, notifies the user to refresh the page (you can custom behavior).

When to check for updates (fetch version.json) ?

  1. first load page.
  2. poll (default: 10 * 60 * 1000 ms).
  3. script resource loading failure detected (404 ?).
  4. when the tab page is refocus or revisible.

Why

Some users do not have the habit of closing web pages. If the front-end page is updated, the user page has always been a historical version, any there may be report an error (file 404) or a white screen.

Install

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

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

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

Usage

vite | umi | webpack

Important: Disable index.html caching!

If index.html is cached, the update notification may still appear after refreshing, so it is necessary to disable the caching of index.html. This is also a best practice for deploy SPA applications.

To disable caching through nginx:

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

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

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

Directly disable caching through html meta tags:

<!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

basic usage

// 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,
    }),
  ]
})

custom notification text

// vite.config.ts
export default defineConfig({
  plugins: [
    vue(),
    webUpdateNotice({
      notificationProps: {
        title: 'system update',
        description: 'System update, please refresh the page',
        buttonText: 'refresh',
      },
    }),
  ]
})

internationalization

// vite.config.ts
export default defineConfig({
  plugins: [
    vue(),
    webUpdateNotice({
      // plugin preset: 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: {
          ...
        },
        ...
      },
    }),
  ],
});


// other file to set locale
window.pluginWebUpdateNotice_.setLocale('zh_CN')

hidden default notification, listener to update event and custom behavior.

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

// other file to listener update event and custom behavior
document.body.addEventListener('plugin_web_update_notice', (e) => {
  const { version, options } = e.detail
  // write some code, show your custom notification and etc.
  alert('System update!')
})

Umijs

// .umirc.ts
import { defineConfig } from 'umi'
import type { Options as WebUpdateNotificationOptions } from '@plugin-web-update-notification/umijs'

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

webpack

// 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,
      }),
    ],
  },
})

suggest: disabled index.html cache

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

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

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

webUpdateNotice Options

function webUpdateNotice(options?: Options): Plugin

export interface Options {
  /**
   * support 'git_commit_hash' | 'svn_revision_number' | 'pkg_version' | 'build_timestamp' | 'custom'
   * * if repository type is 'Git', default is 'git_commit_hash'
   * * if repository type is 'SVN', default is 'svn_revision_number'
   * * if repository type is 'unknown', default is 'build_timestamp'
   * */
  versionType?: VersionType
  /**
   * custom version, if versionType is 'custom', this option is required
   */
  customVersion?: string
  /** polling interval(ms)
   * if set to 0, it will not polling
   * @default 10 * 60 * 1000
   */
  checkInterval?: number
  /**
   * check update when window focus
   * @default true
   */
  checkOnWindowFocus?: boolean
  /**
   * check update immediately after page loaded
   * @default true
   */
  checkImmediately?: boolean
  /**
   * check update when load js file error
   * @default true
   */
  checkOnLoadFileError?: boolean
  /**
   * whether to output version in console
   *
   * you can also pass a function to handle the version
   * ```ts
   * logVersion: (version) => {
   *  console.log(`version: %c${version}`, 'color: #1890ff') // this is the default behavior
   * }
   * ```
   * @default true
   */
  logVersion?: boolean | ((version: string) => void)
  /**
   * whether to silence the notification.
   * such as when local version is v1.0, you can set this option to true and build a new version v1.0.1, then the notification will not show
   */
  silence?: boolean
  /**
   * @deprecated
   */
  customNotificationHTML?: string
  /** notificationProps have higher priority than locale */
  notificationProps?: NotificationProps
  notificationConfig?: NotificationConfig
  /**
   * preset: zh_CN | zh_TW | en_US
   * @default 'zh_CN'
   * */
  locale?: string
  /**
   * custom locale data
   * @link default data: https://github.com/GreatAuk/plugin-web-update-notification/blob/master/packages/core/src/locale.ts
   */
  localeData?: LocaleData
  /**
   * Whether to hide the default notification, if you set it to true, you need to custom behavior by yourself
   * ```ts
    document.body.addEventListener('plugin_web_update_notice', (e) => {
      const { version, options } = e.detail
      // write some code, show your custom notification and etc.
      alert('System update!')
    })
   * ```
   * @default false
   */
  hiddenDefaultNotification?: boolean
  /**
   * Whether to hide the dismiss button
   * @default false
   */
  hiddenDismissButton?: boolean
  /**
   * After version 1.2.0, you not need to set this option, it will be automatically detected from the base of vite config、publicPath of webpack config or publicPath of umi config
   *
   * Base public path for inject file, Valid values include:
   * * Absolute URL pathname, e.g. /foo/
   * * Full URL, e.g. https://foo.com/
   * * Empty string(default) or ./
   *
   * !!! Don't forget / at the end of the path
  */
  injectFileBase?: string
}

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

export interface NotificationConfig {
  /**
   * refresh button color
   * @default '#1677ff'
  */
  primaryColor?: string
  /**
   * dismiss button color
   * @default 'rgba(0,0,0,.25)'
  */
  secondaryColor?: string
  /** @default 'bottomRight' */
  placement?: 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'
}

export interface NotificationProps {
  title?: string
  description?: string
  /** refresh button text */
  buttonText?: string
  /** dismiss button text */
  dismissButtonText?: string
}

export type LocaleData = Record<string, NotificationProps>

export Functions

| name | params | describe | | ----------------------------------------------- | ----------------------------------- | ------------------------------------------------------------ | | window.pluginWebUpdateNotice_.setLocale | locale(preset: zh_CN、zh_TW、en_US) | set locale | | window.pluginWebUpdateNotice_.closeNotification | | close notification | | window.pluginWebUpdateNotice_.dismissUpdate | | dismiss current update and close notification,same behavior as dismiss button | | window.pluginWebUpdateNotice_.checkUpdate | | manual check update, a function wrap by debounce(5000ms) |

interface Window {
  pluginWebUpdateNotice_: {
    /**
       * set language.
       * preset: zh_CN、zh_TW、en_US
      */
    setLocale: (locale: string) => void
    /**
     * manual check update, a function wrap by debounce(5000ms)
     */
    checkUpdate: () => void
    /** dismiss current update and close notification, same behavior as dismiss the button */
    dismissUpdate: () => void
    /** close notification */
    closeNotification: () => void
    /**
     * refresh button click event, if you set it, it will cover the default event (location.reload())
     */
    onClickRefresh?: (version: string) => void
    /**
     * dismiss button click event, if you set it, it will cover the default event (dismissUpdate())
     */
    onClickDismiss?: (version: string) => void
  }
}

What was changed

inject_content

Q&A

  1. TypeScript intellisense, if you use window.pluginWebUpdateNotice_. or listener custom update event。

    // src/shim.d.ts
    
    // if you use vite plugin
    /// <reference types="@plugin-web-update-notification/vite" />
    
    // if you use umi plugin
    /// <reference types="@plugin-web-update-notification/umijs" />
    
    // if you use webpack plugin
    /// <reference types="@plugin-web-update-notification/webpack" />
  2. request version.json file get 404 error.

    If you upload the production files bundled to cdn server:

    // 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
        })
      ]
    })

    Deploy the project in a non-root directory:

    // 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
        })
      ]
    })

    After version 1.2.0, in most case, you not need to set injectFileBase, it will be automatically detected from the base of vite config、publicPath of webpack config or publicPath of umi config

  3. Custom notification button event.

    // refresh button click event, if you set it, it will cover the default event (location.reload())
    window.pluginWebUpdateNotice_.onClickRefresh = (version) => { alert(`click refresh btn: ${version}`) }
    
    // dismiss button click event, if you set it, it will cover the default event (dismissUpdate())
    window.pluginWebUpdateNotice_.onClickDismiss = (version) => { alert(`click dismiss btn: ${version}`) }
  4. Custom notification style.

    you can cover css styles with higher weights. (default css file)

    <!-- notification html content -->
    
    <div class="plugin-web-update-notice-anchor">
      <div class="plugin-web-update-notice">
        <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">
            <a class="plugin-web-update-notice-btn plugin-web-update-notice-dismiss-btn">dismiss</a>
            <a class="plugin-web-update-notice-btn plugin-web-update-notice-refresh-btn">
              refresh
            </a>
          </div>
        </div>
      </div>
    </div>
  5. manual check update.

    // vue-router check update before each route change
    router.beforeEach((to, from, next) => {
      window.pluginWebUpdateNotice_.checkUpdate()
      next()
    })
  6. Some versions do not notify. For example, if the customer version is v1.0, you need to update to v1.0.1, but do not want to display the update prompt.

    webUpdateNotice({
      ...
      silence: true
    })

License

MIT