Skip to content

Commit

Permalink
feat: support dismiss update
Browse files Browse the repository at this point in the history
  • Loading branch information
GreatAuk committed Nov 20, 2022
1 parent 48fd695 commit 58c34a6
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 47 deletions.
3 changes: 2 additions & 1 deletion example/vue-vite/vite.config.ts
Expand Up @@ -12,9 +12,10 @@ export default defineConfig({
logVersion: true,
checkInterval: 0.5 * 60 * 1000,
notificationProps: {
title: "system update",
title: "📢 system update",
description: "System update, please refresh the page",
buttonText: "refresh",
dismissButtonText: "dismiss",
},
}),
],
Expand Down
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -38,7 +38,8 @@
"dist"
],
"scripts": {
"build": "pnpm --filter=./packages/** build",
"build:core": "pnpm --filter=@plugin-web-update-notification/core build",
"build": "pnpm build:core && pnpm --filter=./packages/** --filter=!./packages/core build",
"dev:vite": "pnpm --filter=@plugin-web-update-notification/vite dev",
"dev:umi": "pnpm --filter=@plugin-web-update-notification/core dev",
"dev:webpack": "pnpm --filter=@plugin-web-update-notification/webpack dev",
Expand Down
37 changes: 22 additions & 15 deletions packages/core/public/webUpdateNoticeInjectStyle.css
@@ -1,42 +1,49 @@
.plugin-web-update-notice-anchor {
cursor: pointer;
}
.plugin-web-update-notice {
position: fixed;
right: 24px;
bottom: 24px;
user-select: none;
}

.plugin-web-update-notice-content {
background-color: #fff;
border-radius: 4px;
color: #000000d9;
box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d;
padding: 12px 16px;
padding: 8px 16px;
line-height: 1.5715;
width: 280px;
}

.plugin-web-update-notice-content-title {
font-weight: 500;
margin-bottom: 8px;
margin-bottom: 4px;
font-size: 15px;
line-height: 24px;
}

.plugin-web-update-notice-content-desc {
font-size: 13px;
line-height: 24px;
line-height: 20px;
}
.plugin-web-update-notice-refresh-btn {
position: absolute;
top: 8px;
right: 8px;
padding: 8px 12px;
.plugin-web-update-notice-tools {
margin-top: 4px;
text-align: right;
}
.plugin-web-update-notice-btn {
padding: 3px 8px;
line-height: 1;
border-radius: 4px;
transition: background-color .2s linear;
color: #1890ff;
cursor: pointer;
font-size: 14px;
}

.plugin-web-update-notice-refresh-btn:hover {
background-color: rgba(64,87,109,.1);
.plugin-web-update-notice-btn:hover {
background-color: rgba(64, 87, 109, .1);
}
.plugin-web-update-notice-refresh-btn {
color: #1677ff;
}
.plugin-web-update-notice-dismiss-btn {
color: rgba(0,0,0,.25);
}
10 changes: 6 additions & 4 deletions packages/core/src/constant.ts
@@ -1,10 +1,12 @@
export const JSON_FILE_NAME = 'web_version_by_plugin'

export const INJECT_STYLE_FILE_NAME = 'webUpdateNoticeInjectStyle'

/** .global is iife suffix */
export const INJECT_SCRIPT_FILE_NAME = 'webUpdateNoticeInjectScript.global'

export const CUSTOM_UPDATE_EVENT_NAME = 'system_update_plugin_web_update_notification'

export const NOTIFICATION_ANCHOR_CLASS_NAME = 'plugin-web-update-notice-anchor'

/** refresh button class name */
export const NOTIFICATION_REFRESH_BTN_CLASS_NAME = 'plugin-web-update-notice-refresh-btn'
/** dismiss button class name */
export const NOTIFICATION_DISMISS_BTN_CLASS_NAME = 'plugin-web-update-notice-dismiss-btn'
export const LOCAL_STORAGE_PREFIX = 'web_update_check_dismiss_version_'
78 changes: 54 additions & 24 deletions packages/core/src/script.ts → packages/core/src/injectScript.ts
@@ -1,11 +1,8 @@
import type { Options } from './type'
import { CUSTOM_UPDATE_EVENT_NAME, JSON_FILE_NAME, NOTIFICATION_ANCHOR_CLASS_NAME } from './constant'
import { CUSTOM_UPDATE_EVENT_NAME, JSON_FILE_NAME, LOCAL_STORAGE_PREFIX, NOTIFICATION_ANCHOR_CLASS_NAME, NOTIFICATION_DISMISS_BTN_CLASS_NAME, NOTIFICATION_REFRESH_BTN_CLASS_NAME } from './constant'

// bind notification click event, click to refresh page
const anchor = document.querySelector(`.${NOTIFICATION_ANCHOR_CLASS_NAME}`)
anchor?.addEventListener('click', () => {
window.location.reload()
})
let hasShowSystemUpdateNotice = false
let latestVersion = ''

/**
* limit function
Expand Down Expand Up @@ -34,24 +31,25 @@ function webUpdateCheck_checkAndNotice(options: Options) {
const { injectFileBase = '', checkInterval, hiddenDefaultNotification } = options
const checkSystemUpdate = () => {
window
.fetch(`${injectFileBase}${JSON_FILE_NAME}.json?t=${Date.now()}`)
.fetch(`${injectFileBase}${JSON_FILE_NAME}.json?t=${performance.now()}`)
.then((response) => {
if (!response.ok)
throw new Error(`Failed to fetch ${JSON_FILE_NAME}.json`)

return response.json()
})
.then((res) => {
if (window.web_version_by_plugin !== res.version) {
.then(({ version: versionFromServer }: { version: string }) => {
latestVersion = versionFromServer
if (window.web_version_by_plugin !== versionFromServer) {
// dispatch custom event
document.body.dispatchEvent(new CustomEvent(CUSTOM_UPDATE_EVENT_NAME, {
detail: options,
bubbles: true,
}))
if (!window.hasShowSystemUpdateNotice_plugin && !hiddenDefaultNotification) {
webUpdateCheck_showNotification(options)
// eslint-disable-next-line no-console
console.log('system has update!!!')
}

const dismiss = localStorage.getItem(`${LOCAL_STORAGE_PREFIX}${versionFromServer}`) === 'true'
if (!hasShowSystemUpdateNotice && !hiddenDefaultNotification && !dismiss)
handleShowNotification(options)
}
})
.catch((err) => {
Expand Down Expand Up @@ -93,13 +91,38 @@ function webUpdateCheck_checkAndNotice(options: Options) {
}
window.webUpdateCheck_checkAndNotice = webUpdateCheck_checkAndNotice

/**
* Bind the refresh button click event to refresh the page, and bind the dismiss button click event to
* hide the notification and dismiss the system update.
*/
function bindBtnEvent() {
// bind refresh button click event, click to refresh page
const refreshBtn = document.querySelector(`.${NOTIFICATION_REFRESH_BTN_CLASS_NAME}`)
refreshBtn?.addEventListener('click', () => {
window.location.reload()
})

// bind dismiss button click event, click to hide notification
const dismissBtn = document.querySelector(`.${NOTIFICATION_DISMISS_BTN_CLASS_NAME}`)
dismissBtn?.addEventListener('click', () => {
try {
hasShowSystemUpdateNotice = false
document.querySelector(`.${NOTIFICATION_ANCHOR_CLASS_NAME}`)?.remove()
localStorage.setItem(`${LOCAL_STORAGE_PREFIX}${latestVersion}`, 'true')
}
catch (err) {
console.error(err)
}
})
}

/**
* show update notification
*/
function webUpdateCheck_showNotification(options: Options) {
window.hasShowSystemUpdateNotice_plugin = true
function handleShowNotification(options: Options) {
hasShowSystemUpdateNotice = true

const { notificationProps, customNotificationHTML } = options
const { notificationProps, customNotificationHTML, hiddenDismissButton } = options

const notification = document.createElement('div')
let notificationInnerHTML = ''
Expand All @@ -108,9 +131,11 @@ function webUpdateCheck_showNotification(options: Options) {
notificationInnerHTML = customNotificationHTML
}
else {
const title = notificationProps?.title || '📢  系统升级通知'
const description = notificationProps?.description || '检测到当前系统版本已更新,请刷新页面后使用。'
const buttonText = notificationProps?.buttonText || '刷新'
const title = notificationProps?.title ?? '📢  系统升级通知'
const description = notificationProps?.description ?? '检测到当前系统版本已更新,请刷新页面后使用。'
const buttonText = notificationProps?.buttonText ?? '刷新'
const dismissButtonText = notificationProps?.dismissButtonText ?? '忽略'
const dismissButtonHtml = hiddenDismissButton ? '' : `<a class="plugin-web-update-notice-btn plugin-web-update-notice-dismiss-btn">${dismissButtonText}</a>`
notification.classList.add('plugin-web-update-notice')
notificationInnerHTML = `
<div class="plugin-web-update-notice-content" data-cy="notification-content">
Expand All @@ -120,20 +145,25 @@ function webUpdateCheck_showNotification(options: Options) {
<div class="plugin-web-update-notice-content-desc">
${description}
</div>
<a class="plugin-web-update-notice-refresh-btn">
${buttonText}
</a>
<div class="plugin-web-update-notice-tools">
${dismissButtonHtml}
<a class="plugin-web-update-notice-btn plugin-web-update-notice-refresh-btn">
${buttonText}
</a>
</div>
</div>`
}

notification.innerHTML = notificationInnerHTML
document
.querySelector(`.${NOTIFICATION_ANCHOR_CLASS_NAME}`)!
.appendChild(notification)

bindBtnEvent()
}

// meaningless export, in order to let tsup bundle these functions
export {
webUpdateCheck_checkAndNotice,
webUpdateCheck_showNotification,
handleShowNotification as webUpdateCheck_showNotification,
}
4 changes: 4 additions & 0 deletions packages/core/src/type.ts
Expand Up @@ -6,6 +6,7 @@ export interface Options {
customNotificationHTML?: string
notificationProps?: NotificationProps
hiddenDefaultNotification?: boolean
hiddenDismissButton?: boolean
/**
* Base public path for inject file, Valid values include:
* * Absolute URL pathname, e.g. /foo/
Expand All @@ -18,5 +19,8 @@ export interface Options {
interface NotificationProps {
title?: string
description?: string
/** refresh button text */
buttonText?: string
/** dismiss button text */
dismissButtonText?: string
}
2 changes: 1 addition & 1 deletion packages/core/tsup.config.ts
Expand Up @@ -5,7 +5,7 @@ export default defineConfig((options) => { // The options here is derived from C
return {
entry: {
index: 'src/index.ts',
[INJECT_SCRIPT_FILE_NAME.replace('.global', '')]: 'src/script.ts',
[INJECT_SCRIPT_FILE_NAME.replace('.global', '')]: 'src/injectScript.ts',
pluginBuildScript: 'src/pluginBuildScript.ts',
},
splitting: false,
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es2018",
"target": "es2020",
"module": "esnext",
"lib": ["esnext"],
"moduleResolution": "node",
Expand Down

0 comments on commit 58c34a6

Please sign in to comment.