From 053421b0f1ad0714ad0375e40f5ea4c3054e043a Mon Sep 17 00:00:00 2001 From: Faizal Andyka Date: Sun, 22 Aug 2021 01:56:27 +0700 Subject: [PATCH] feat: handle error after release --- env/env.dev | 1 + env/env.prod | 1 + package.json | 2 ++ pnpm-lock.yaml | 13 +++++++++++++ src/modules/About/router.ts | 7 ++++++- src/modules/Home/router.ts | 7 ++++++- src/utils/filters.ts | 3 +++ src/utils/routerGuard.ts | 26 +++++++++++++++++++++++++- src/utils/storage.ts | 22 ++++++++++++++++++++++ 9 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 src/utils/filters.ts create mode 100644 src/utils/storage.ts diff --git a/env/env.dev b/env/env.dev index 6536916..9d46625 100644 --- a/env/env.dev +++ b/env/env.dev @@ -1,3 +1,4 @@ VITE_API_URL = / VITE_TIMEOUT = 20000 VITE_EXPIRED = 30 +VITE_STORAGE_ERROR_PAGE = erpg diff --git a/env/env.prod b/env/env.prod index 6536916..9d46625 100644 --- a/env/env.prod +++ b/env/env.prod @@ -1,3 +1,4 @@ VITE_API_URL = / VITE_TIMEOUT = 20000 VITE_EXPIRED = 30 +VITE_STORAGE_ERROR_PAGE = erpg diff --git a/package.json b/package.json index 87bfccc..2b9124c 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "@iconify/json": "^1.1.390", "@intlify/vite-plugin-vue-i18n": "^2.4.0", "@rollup/plugin-yaml": "^3.1.0", + "@types/js-cookie": "^2.2.7", "@vitejs/plugin-legacy": "^1.5.1", "@vitejs/plugin-vue": "^1.4.0", "@vue/compiler-sfc": "^3.2.4", @@ -94,6 +95,7 @@ "dotenv-cli": "^4.0.0", "element-plus": "1.0.2-beta.44", "husky": "^7.0.1", + "js-cookie": "^3.0.0", "postcss": "^8.3.6", "postcss-import": "^14.0.2", "rimraf": "^3.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 300bd49..52311d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,6 +9,7 @@ specifiers: '@testing-library/jest-dom': ^5.14.1 '@testing-library/vue': ^6.5.0 '@types/jest': ^26.0.24 + '@types/js-cookie': ^2.2.7 '@typescript-eslint/eslint-plugin': ^4.29.2 '@typescript-eslint/parser': ^4.29.2 '@vitejs/plugin-legacy': ^1.5.1 @@ -38,6 +39,7 @@ specifiers: jest-serializer-vue: ^2.0.2 jest-transform-stub: ^2.0.0 jest-watch-typeahead: ^0.6.4 + js-cookie: ^3.0.0 postcss: ^8.3.6 postcss-import: ^14.0.2 rimraf: ^3.0.2 @@ -68,6 +70,7 @@ dependencies: '@iconify/json': 1.1.391 '@intlify/vite-plugin-vue-i18n': 2.4.0_4cef02acf2f8b9c8009dbbdef0b0dc6c '@rollup/plugin-yaml': 3.1.0 + '@types/js-cookie': 2.2.7 '@vitejs/plugin-legacy': 1.5.1_vite@2.5.0 '@vitejs/plugin-vue': 1.4.0_@vue+compiler-sfc@3.2.4 '@vue/compiler-sfc': 3.2.4 @@ -82,6 +85,7 @@ dependencies: dotenv-cli: 4.0.0 element-plus: 1.0.2-beta.44_vue@3.2.4 husky: 7.0.1 + js-cookie: 3.0.0 postcss: 8.3.6 postcss-import: 14.0.2_postcss@8.3.6 rimraf: 3.0.2 @@ -1387,6 +1391,10 @@ packages: pretty-format: 26.6.2 dev: true + /@types/js-cookie/2.2.7: + resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==} + dev: false + /@types/json-schema/7.0.9: resolution: {integrity: sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==} dev: true @@ -5376,6 +5384,11 @@ packages: nopt: 5.0.0 dev: true + /js-cookie/3.0.0: + resolution: {integrity: sha512-oUbbplKuH07/XX2YD2+Q+GMiPpnVXaRz8npE7suhBH9QEkJe2W7mQ6rwuMXHue3fpfcftQwzgyvGzIHyfCSngQ==} + engines: {node: '>=12'} + dev: false + /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} diff --git a/src/modules/About/router.ts b/src/modules/About/router.ts index 14ed374..a66fbed 100644 --- a/src/modules/About/router.ts +++ b/src/modules/About/router.ts @@ -2,7 +2,12 @@ const routes: {}[] = [ { path: '/about', name: 'about.index', - component: () => import('./views/about.vue') + component: (): Promise => { + return new Promise((resolve, reject) => { + resolve(import('./views/about.vue')) + reject(new Error('Failed to load page')) + }) + } } ] diff --git a/src/modules/Home/router.ts b/src/modules/Home/router.ts index cecc504..83206c9 100644 --- a/src/modules/Home/router.ts +++ b/src/modules/Home/router.ts @@ -2,7 +2,12 @@ const routes: {}[] = [ { path: '/', name: 'home.index', - component: () => import('./views/home.vue') + component: (): Promise => { + return new Promise((resolve, reject) => { + resolve(import('./views/home.vue')) + reject(new Error('Failed to load page')) + }) + } } ] diff --git a/src/utils/filters.ts b/src/utils/filters.ts new file mode 100644 index 0000000..723e7ba --- /dev/null +++ b/src/utils/filters.ts @@ -0,0 +1,3 @@ +export const isUndefined = (value: number | string | {} | [] | {}[]): boolean => { + return value === undefined +} diff --git a/src/utils/routerGuard.ts b/src/utils/routerGuard.ts index cb30913..b37dde8 100644 --- a/src/utils/routerGuard.ts +++ b/src/utils/routerGuard.ts @@ -1,5 +1,10 @@ import { Router } from 'vue-router' import { useNProgress } from '@vueuse/integrations' +import { + setErrorPage, + getErrorPage, + delErrorPage +} from './storage' const { start, done } = useNProgress(null, { showSpinner: false @@ -16,6 +21,17 @@ const routerGuard: Function = (router: Router) => { }) router.afterEach(() => { + /** + * DESC: + * navigate to the page that is + * defined after router.onError + */ + const errorPage = getErrorPage() + if (errorPage.length) { + router.push({ name: errorPage }) + delErrorPage() + } + /** * DESC: * end progress bar @@ -23,7 +39,15 @@ const routerGuard: Function = (router: Router) => { done() }) - router.onError(() => { + router.onError((error, to) => { + /** + * DESC: + * force users to reload their browser and + * navigate it to the page that they want to visit + * to achieve smooth code update after release + */ + console.error(error) + setErrorPage(String(to.name)) location.reload() }) diff --git a/src/utils/storage.ts b/src/utils/storage.ts new file mode 100644 index 0000000..6c0085f --- /dev/null +++ b/src/utils/storage.ts @@ -0,0 +1,22 @@ +import cookie from 'js-cookie' +import { isUndefined } from './filters' + +const expired = Number(import.meta.env.VITE_EXPIRED) +const storageErrorPage = String(import.meta.env.VITE_STORAGE_ERROR_PAGE) + +export const setErrorPage = ( + name: string, + expires = expired +): void => { + if (!isUndefined(name)) { + cookie.set(storageErrorPage, name, { expires }) + } +} + +export const getErrorPage = (): string => { + return cookie.get(storageErrorPage) || '' +} + +export const delErrorPage = (): void => { + cookie.remove(storageErrorPage) +}