From dc42d434f0b2a3b269deb76d857b42340bd93e80 Mon Sep 17 00:00:00 2001 From: vben Date: Sun, 8 Nov 2020 23:13:47 +0800 Subject: [PATCH] refactor: refactoring menu generation --- .env | 4 ++ CHANGELOG.zh_CN.md | 4 ++ build/vite/plugin/dynamicImport/index.ts | 55 ++++++++++++++++++++++++ mock/sys/menu.ts | 14 +++--- src/layouts/default/index.tsx | 4 +- src/settings/projectSetting.ts | 7 +-- src/store/modules/permission.ts | 8 ++-- src/utils/env.ts | 12 ++++++ src/utils/helper/dynamicImport.ts | 4 ++ src/utils/helper/routeHelper.ts | 8 ++-- vite.config.ts | 3 +- 11 files changed, 104 insertions(+), 19 deletions(-) create mode 100644 build/vite/plugin/dynamicImport/index.ts create mode 100644 src/utils/helper/dynamicImport.ts diff --git a/.env b/.env index fdd62d5c..1545fae6 100644 --- a/.env +++ b/.env @@ -6,3 +6,7 @@ VITE_GLOB_APP_TITLE = Vben Admin # spa shortname VITE_GLOB_APP_SHORT_NAME = vue_vben_admin_2x + +# Menu generation mode BACK|ROLE +# Need to delete LocalStorage after modification +VITE_GEN_MENU_MODE=ROLE diff --git a/CHANGELOG.zh_CN.md b/CHANGELOG.zh_CN.md index cdaa80d4..6dcc2b4b 100644 --- a/CHANGELOG.zh_CN.md +++ b/CHANGELOG.zh_CN.md @@ -8,6 +8,10 @@ - openModal 和 openDrawer 第二个参数可以代替`transferModalData`传参到内部 - 带参路由可以被缓存 +### ✨ Refactor + +- 重构由后台生成菜单的逻辑 + ### ⚡ Performance Improvements - 菜单性能继续优化,更流畅 diff --git a/build/vite/plugin/dynamicImport/index.ts b/build/vite/plugin/dynamicImport/index.ts new file mode 100644 index 00000000..6b0b92ce --- /dev/null +++ b/build/vite/plugin/dynamicImport/index.ts @@ -0,0 +1,55 @@ +// Used to import all files under `src/views` + +// The built-in dynamic import of vite cannot meet the needs of importing all files under views + +import glob from 'glob'; +import { Transform } from 'vite/dist/node/transform.js'; + +function getPath(path: string) { + const lastIndex = path.lastIndexOf('.'); + if (lastIndex !== -1) { + path = path.substring(0, lastIndex); + } + return path.replace('src/views', ''); +} + +const dynamicImportTransform = function (env: any = {}): Transform { + return { + test({ path }) { + // Only convert the file + return path.includes('/src/utils/helper/dynamicImport.ts'); + }, + transform({ code }) { + const { VITE_GEN_MENU_MODE = '' } = env; + if (VITE_GEN_MENU_MODE !== 'BACK') { + return code; + } + // if (!isBuild) return code; + // Only convert the dir + try { + const files = glob.sync('src/views/**/**.{vue,tsx}', { cwd: process.cwd() }); + + const _code = ` + export default function (id) { + switch (id) { + ${files + + .map((p) => + ` case '${getPath(p)}': return () => import('${p + .replace('src/views', '/@/views') + .replace(/\/\//g, '/')}');`.replace('.tsx', '') + ) + .join('\n ')} + default: return Promise.reject(new Error("Unknown variable dynamic import: " + id)); + } + }\n\n + `; + return _code; + } catch (error) { + console.error(error); + return code; + } + }, + }; +}; +export default dynamicImportTransform; diff --git a/mock/sys/menu.ts b/mock/sys/menu.ts index 2f962325..82930c54 100644 --- a/mock/sys/menu.ts +++ b/mock/sys/menu.ts @@ -16,7 +16,7 @@ const dashboardRoute = { { path: '/welcome', name: 'Welcome', - component: '/dashboard/welcome/index.vue', + component: '/dashboard/welcome/index', meta: { title: '欢迎页', affix: true, @@ -34,28 +34,28 @@ const frontRoute = { children: [ { path: 'page', - component: '/demo/permission/front/index.vue', + component: '/demo/permission/front/index', meta: { title: '页面权限', }, }, { path: 'btn', - component: '/demo/permission/front/Btn.vue', + component: '/demo/permission/front/Btn', meta: { title: '按钮权限', }, }, { path: 'auth-pageA', - component: '/demo/permission/front/AuthPageA.vue', + component: '/demo/permission/front/AuthPageA', meta: { title: '权限测试页A', }, }, { path: 'auth-pageB', - component: '/demo/permission/front/AuthPageB.vue', + component: '/demo/permission/front/AuthPageB', meta: { title: '权限测试页B', }, @@ -71,14 +71,14 @@ const backRoute = { children: [ { path: 'page', - component: 'demo/permission/back/index.vue', + component: '/demo/permission/back/index', meta: { title: '页面权限', }, }, { path: 'btn', - component: '/demo/permission/back/Btn.vue', + component: '/demo/permission/back/Btn', meta: { title: '按钮权限', }, diff --git a/src/layouts/default/index.tsx b/src/layouts/default/index.tsx index a4b11262..3116e096 100644 --- a/src/layouts/default/index.tsx +++ b/src/layouts/default/index.tsx @@ -107,7 +107,9 @@ export default defineComponent({ unref(showHeaderRef) && } {showTabs && !unref(getFullContent) && ( - + + {() => } + )} {useOpenBackTop && } diff --git a/src/settings/projectSetting.ts b/src/settings/projectSetting.ts index ff08bb3f..2ca2ea44 100644 --- a/src/settings/projectSetting.ts +++ b/src/settings/projectSetting.ts @@ -1,15 +1,16 @@ import type { ProjectConfig } from '/@/types/config'; import { MenuTypeEnum, MenuThemeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum'; -import { ContentEnum, PermissionModeEnum, RouterTransitionEnum } from '/@/enums/appEnum'; +import { ContentEnum, RouterTransitionEnum } from '/@/enums/appEnum'; import { primaryColor } from '../../build/config/lessModifyVars'; -import { isProdMode } from '/@/utils/env'; +import { isProdMode, getRoleMode } from '/@/utils/env'; + // ! You need to clear the browser cache after the change const setting: ProjectConfig = { // Whether to show the configuration button showSettingButton: true, // 权限模式 - permissionMode: PermissionModeEnum.ROLE, + permissionMode: getRoleMode(), // 网站灰色模式,用于可能悼念的日期开启 grayMode: false, // 色弱模式 diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts index 3b50634e..4f3e9578 100644 --- a/src/store/modules/permission.ts +++ b/src/store/modules/permission.ts @@ -19,7 +19,7 @@ import { genRouteModule, transformObjToRoute } from '/@/utils/helper/routeHelper import { transformRouteToMenu } from '/@/utils/helper/menuHelper'; import { useMessage } from '/@/hooks/web/useMessage'; -import { warn } from '/@/utils/log'; +// import { warn } from '/@/utils/log'; const { createMessage } = useMessage(); const NAME = 'permission'; @@ -99,9 +99,9 @@ class Permission extends VuexModule { }); // this.commitRoutesState(routes); // Background permissions - warn( - `当前权限模式为:${PermissionModeEnum.ROLE},请将src/store/modules/permission.ts内的后台菜单获取函数注释,如果已注释可以忽略此信息!` - ); + // warn( + // `当前权限模式为:${PermissionModeEnum.ROLE},请将src/store/modules/permission.ts内的后台菜单获取函数注释,如果已注释可以忽略此信息!` + // ); // 如果确定不需要做后台动态权限,请将下面整个判断注释 } else if (permissionMode === PermissionModeEnum.BACK) { const messageKey = 'loadMenu'; diff --git a/src/utils/env.ts b/src/utils/env.ts index 58818a72..a14a6f31 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -1,3 +1,4 @@ +import { PermissionModeEnum } from '../enums/appEnum'; import type { GlobEnvConfig } from '/@/types/config'; export const getGlobEnvConfig = (): GlobEnvConfig => { @@ -46,3 +47,14 @@ export const isProdMode = (): boolean => import.meta.env.PROD; * @example: */ export const isUseMock = (): boolean => import.meta.env.VITE_USE_MOCK === 'true'; + +/** + * @description: 获取菜单生成方式 + * @param {type} + * @returns: + * @example: + */ +export const getRoleMode = (): PermissionModeEnum => + import.meta.env.VITE_GEN_MENU_MODE === PermissionModeEnum.ROLE + ? PermissionModeEnum.ROLE + : PermissionModeEnum.BACK; diff --git a/src/utils/helper/dynamicImport.ts b/src/utils/helper/dynamicImport.ts new file mode 100644 index 00000000..34e5b08a --- /dev/null +++ b/src/utils/helper/dynamicImport.ts @@ -0,0 +1,4 @@ +export default function (id: string) { + const dynamicImportModule: any = id; + return dynamicImportModule; +} diff --git a/src/utils/helper/routeHelper.ts b/src/utils/helper/routeHelper.ts index eab722a1..274f0341 100644 --- a/src/utils/helper/routeHelper.ts +++ b/src/utils/helper/routeHelper.ts @@ -6,6 +6,8 @@ import { tabStore } from '/@/store/modules/tab'; import { createRouter, createWebHashHistory } from 'vue-router'; import { toRaw } from 'vue'; import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant'; +// import { isDevMode } from '/@/utils/env'; +import dynamicImport from './dynamicImport'; let currentTo: RouteLocationNormalized | null = null; @@ -45,12 +47,12 @@ export function genRouteModule(moduleList: AppRouteModule[]) { // TODO 错误写法 function asyncImportRoute(routes: AppRouteRecordRaw[]) { routes.forEach((item) => { - let { component } = item; + const { component } = item; const { children } = item; if (component) { - component = component.replace(/^\//, ''); - item.component = () => import(`/@/views/${component}`); + item.component = dynamicImport(component); } + children && asyncImportRoute(children); }); } diff --git a/vite.config.ts b/vite.config.ts index 679c90ae..39a6b5cd 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,6 +5,7 @@ import { resolve } from 'path'; import { modifyVars } from './build/config/lessModifyVars'; import { createProxy } from './build/vite/proxy'; import globbyTransform from './build/vite/plugin/context/transform'; +import dynamicImportTransform from './build/vite/plugin/dynamicImport/index'; import { isDevFn, loadEnv } from './build/utils'; @@ -134,5 +135,5 @@ const viteConfig: UserConfig = { export default { ...viteConfig, - transforms: [globbyTransform(viteConfig)], + transforms: [globbyTransform(viteConfig), dynamicImportTransform(viteEnv)], } as UserConfig; -- GitLab