diff --git a/package-lock.json b/package-lock.json index 3e08ab14..cdcaec9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "postcss-preset-env": "~8.0.1", "twitter-text": "~3.1.0", "vite": "~4.1.4", + "vite-plugin-generate-file": "~0.0.4", "vite-plugin-html-config": "~1.0.11", "vite-plugin-html-env": "~1.2.7", "vite-plugin-pwa": "~0.14.4", @@ -3099,6 +3100,12 @@ "node": ">=4" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/async": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", @@ -4541,6 +4548,18 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -6631,6 +6650,88 @@ } } }, + "node_modules/vite-plugin-generate-file": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vite-plugin-generate-file/-/vite-plugin-generate-file-0.0.4.tgz", + "integrity": "sha512-5cdsdSRGdtUxbAGdaXlW3Wiy46lK7LYm2FaTy42KCFT9fS6kiR+Ynjsjt7UEuE4nfStvCS9bVk9+YtsEIJ+Vhw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "ejs": "^3.1.6", + "js-yaml": "^4.1.0", + "mime-types": "^2.1.35" + } + }, + "node_modules/vite-plugin-generate-file/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/vite-plugin-generate-file/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/vite-plugin-generate-file/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/vite-plugin-generate-file/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/vite-plugin-generate-file/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/vite-plugin-generate-file/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/vite-plugin-html-config": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/vite-plugin-html-config/-/vite-plugin-html-config-1.0.11.tgz", @@ -9078,6 +9179,12 @@ "color-convert": "^1.9.0" } }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "async": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", @@ -10127,6 +10234,15 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -11518,6 +11634,69 @@ "rollup": "^3.10.0" } }, + "vite-plugin-generate-file": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vite-plugin-generate-file/-/vite-plugin-generate-file-0.0.4.tgz", + "integrity": "sha512-5cdsdSRGdtUxbAGdaXlW3Wiy46lK7LYm2FaTy42KCFT9fS6kiR+Ynjsjt7UEuE4nfStvCS9bVk9+YtsEIJ+Vhw==", + "dev": true, + "requires": { + "chalk": "^4.1.2", + "ejs": "^3.1.6", + "js-yaml": "^4.1.0", + "mime-types": "^2.1.35" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "vite-plugin-html-config": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/vite-plugin-html-config/-/vite-plugin-html-config-1.0.11.tgz", diff --git a/package.json b/package.json index 60c150f7..bc5bff5d 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "postcss-preset-env": "~8.0.1", "twitter-text": "~3.1.0", "vite": "~4.1.4", + "vite-plugin-generate-file": "~0.0.4", "vite-plugin-html-config": "~1.0.11", "vite-plugin-html-env": "~1.2.7", "vite-plugin-pwa": "~0.14.4", diff --git a/src/app.jsx b/src/app.jsx index e05a40b8..c492d544 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -19,8 +19,6 @@ import { useSnapshot } from 'valtio'; import Account from './components/account'; import Compose from './components/compose'; import Drafts from './components/drafts'; -import Icon from './components/icon'; -import Link from './components/link'; import Loader from './components/loader'; import MediaModal from './components/media-modal'; import Modal from './components/modal'; @@ -56,6 +54,7 @@ import showToast from './utils/show-toast'; import states, { getStatus, saveStatus } from './utils/states'; import store from './utils/store'; import { getCurrentAccount } from './utils/store-utils'; +import useInterval from './utils/useInterval'; import usePageVisibility from './utils/usePageVisibility'; window.__STATES__ = states; @@ -241,6 +240,18 @@ function App() { return !/^\/(login|welcome)/.test(pathname); }, [location]); + useInterval(() => { + console.log('✨ Check app update'); + fetch('./version.json') + .then((r) => r.json()) + .then((info) => { + if (info) states.appVersion = info; + }) + .catch((e) => { + console.error(e); + }); + }, visible && 1000 * 60 * 60); // 1 hour + return ( <> diff --git a/src/components/icon.jsx b/src/components/icon.jsx index 3e84b2f4..dd96894e 100644 --- a/src/components/icon.jsx +++ b/src/components/icon.jsx @@ -61,6 +61,7 @@ const ICONS = { link: 'mingcute:link-2-line', history: 'mingcute:history-line', share: 'mingcute:share-2-line', + sparkles: 'mingcute:sparkles-line', }; const modules = import.meta.glob('/node_modules/@iconify-icons/mingcute/*.js'); diff --git a/src/components/menu.jsx b/src/components/menu.jsx index d1b3b791..c7ca39f0 100644 --- a/src/components/menu.jsx +++ b/src/components/menu.jsx @@ -34,6 +34,27 @@ function NavMenu(props) { } > + {!!snapStates.appVersion?.commitHash && + __COMMIT_HASH__ !== snapStates.appVersion.commitHash && ( + <> + { + const yes = confirm('Reload page now to update?'); + if (yes) { + (async () => { + try { + location.reload(); + } catch (e) {} + })(); + } + }} + > + {' '} + New update available… + + + + )} Home diff --git a/src/utils/states.js b/src/utils/states.js index 44ca5119..abf6d378 100644 --- a/src/utils/states.js +++ b/src/utils/states.js @@ -6,6 +6,7 @@ import { api } from './api'; import store from './store'; const states = proxy({ + appVersion: {}, // history: [], prevLocation: null, currentLocation: null, diff --git a/vite.config.js b/vite.config.js index e743151c..1998c922 100644 --- a/vite.config.js +++ b/vite.config.js @@ -3,6 +3,7 @@ import { execSync } from 'child_process'; import fs from 'fs'; import { resolve } from 'path'; import { defineConfig, loadEnv, splitVendorChunkPlugin } from 'vite'; +import generateFile from 'vite-plugin-generate-file'; import htmlPlugin from 'vite-plugin-html-config'; import VitePluginHtmlEnv from 'vite-plugin-html-env'; import { VitePWA } from 'vite-plugin-pwa'; @@ -12,6 +13,7 @@ const { NODE_ENV } = process.env; const { VITE_CLIENT_NAME: CLIENT_NAME, VITE_APP_ERROR_LOGGING: ERROR_LOGGING } = loadEnv('production', process.cwd()); +const now = new Date(); const commitHash = execSync('git rev-parse --short HEAD').toString().trim(); const rollbarCode = fs.readFileSync( @@ -23,7 +25,7 @@ const rollbarCode = fs.readFileSync( export default defineConfig({ mode: NODE_ENV, define: { - __BUILD_TIME__: JSON.stringify(Date.now()), + __BUILD_TIME__: JSON.stringify(now), __COMMIT_HASH__: JSON.stringify(commitHash), }, plugins: [ @@ -36,6 +38,16 @@ export default defineConfig({ htmlPlugin({ headScripts: ERROR_LOGGING ? [rollbarCode] : [], }), + generateFile([ + { + type: 'json', + output: './version.json', + data: { + buildTime: now, + commitHash, + }, + }, + ]), VitePWA({ manifest: { name: CLIENT_NAME,