perf: optimize bootstrap modules to speed up first-screen loading (#5899)

优化首屏加载速度
This commit is contained in:
Netfan 2025-04-09 01:05:20 +08:00 committed by GitHub
parent 9379093a4f
commit 329a176a5c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 311 additions and 115 deletions

View File

@ -8,35 +8,64 @@ import type { Component } from 'vue';
import type { BaseFormComponentType } from '@vben/common-ui'; import type { BaseFormComponentType } from '@vben/common-ui';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
import { defineComponent, getCurrentInstance, h, ref } from 'vue'; import {
defineAsyncComponent,
defineComponent,
getCurrentInstance,
h,
ref,
} from 'vue';
import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui'; import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
import { import { notification } from 'ant-design-vue';
AutoComplete,
Button, const AutoComplete = defineAsyncComponent(
Checkbox, () => import('ant-design-vue/es/auto-complete'),
CheckboxGroup, );
DatePicker, const Button = defineAsyncComponent(() => import('ant-design-vue/es/button'));
Divider, const Checkbox = defineAsyncComponent(
Input, () => import('ant-design-vue/es/checkbox'),
InputNumber, );
InputPassword, const CheckboxGroup = defineAsyncComponent(() =>
Mentions, import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup),
notification, );
Radio, const DatePicker = defineAsyncComponent(
RadioGroup, () => import('ant-design-vue/es/date-picker'),
RangePicker, );
Rate, const Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider'));
Select, const Input = defineAsyncComponent(() => import('ant-design-vue/es/input'));
Space, const InputNumber = defineAsyncComponent(
Switch, () => import('ant-design-vue/es/input-number'),
Textarea, );
TimePicker, const InputPassword = defineAsyncComponent(() =>
TreeSelect, import('ant-design-vue/es/input').then((res) => res.InputPassword),
Upload, );
} from 'ant-design-vue'; const Mentions = defineAsyncComponent(
() => import('ant-design-vue/es/mentions'),
);
const Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio'));
const RadioGroup = defineAsyncComponent(() =>
import('ant-design-vue/es/radio').then((res) => res.RadioGroup),
);
const RangePicker = defineAsyncComponent(() =>
import('ant-design-vue/es/date-picker').then((res) => res.RangePicker),
);
const Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate'));
const Select = defineAsyncComponent(() => import('ant-design-vue/es/select'));
const Space = defineAsyncComponent(() => import('ant-design-vue/es/space'));
const Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch'));
const Textarea = defineAsyncComponent(() =>
import('ant-design-vue/es/input').then((res) => res.Textarea),
);
const TimePicker = defineAsyncComponent(
() => import('ant-design-vue/es/time-picker'),
);
const TreeSelect = defineAsyncComponent(
() => import('ant-design-vue/es/tree-select'),
);
const Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload'));
const withDefaultPlaceholder = <T extends Component>( const withDefaultPlaceholder = <T extends Component>(
component: T, component: T,

View File

@ -1,8 +1,7 @@
import { createApp, watchEffect } from 'vue'; import { createApp, watchEffect } from 'vue';
import { registerAccessDirective } from '@vben/access'; import { registerAccessDirective } from '@vben/access';
import { initTippy, registerLoadingDirective } from '@vben/common-ui'; import { registerLoadingDirective } from '@vben/common-ui/es/loading';
import { MotionPlugin } from '@vben/plugins/motion';
import { preferences } from '@vben/preferences'; import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores'; import { initStores } from '@vben/stores';
import '@vben/styles'; import '@vben/styles';
@ -47,12 +46,14 @@ async function bootstrap(namespace: string) {
registerAccessDirective(app); registerAccessDirective(app);
// 初始化 tippy // 初始化 tippy
const { initTippy } = await import('@vben/common-ui/es/tippy');
initTippy(app); initTippy(app);
// 配置路由及路由守卫 // 配置路由及路由守卫
app.use(router); app.use(router);
// 配置Motion插件 // 配置Motion插件
const { MotionPlugin } = await import('@vben/plugins/motion');
app.use(MotionPlugin); app.use(MotionPlugin);
// 动态更新标题 // 动态更新标题

View File

@ -2,10 +2,10 @@ import type { RouteRecordRaw } from 'vue-router';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants'; import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { AuthPageLayout, BasicLayout } from '#/layouts';
import { $t } from '#/locales'; import { $t } from '#/locales';
import Login from '#/views/_core/authentication/login.vue';
const BasicLayout = () => import('#/layouts/basic.vue');
const AuthPageLayout = () => import('#/layouts/auth.vue');
/** 全局404页面 */ /** 全局404页面 */
const fallbackNotFoundRoute: RouteRecordRaw = { const fallbackNotFoundRoute: RouteRecordRaw = {
component: () => import('#/views/_core/fallback/not-found.vue'), component: () => import('#/views/_core/fallback/not-found.vue'),
@ -50,7 +50,7 @@ const coreRoutes: RouteRecordRaw[] = [
{ {
name: 'Login', name: 'Login',
path: 'login', path: 'login',
component: Login, component: () => import('#/views/_core/authentication/login.vue'),
meta: { meta: {
title: $t('page.auth.login'), title: $t('page.auth.login'),
}, },

View File

@ -8,31 +8,121 @@ import type { Component } from 'vue';
import type { BaseFormComponentType } from '@vben/common-ui'; import type { BaseFormComponentType } from '@vben/common-ui';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
import { defineComponent, getCurrentInstance, h, ref } from 'vue'; import {
defineAsyncComponent,
defineComponent,
getCurrentInstance,
h,
ref,
} from 'vue';
import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui'; import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
import { import { ElNotification } from 'element-plus';
ElButton,
ElCheckbox, const ElButton = defineAsyncComponent(() =>
ElCheckboxButton, Promise.all([
ElCheckboxGroup, import('element-plus/es/components/button/index'),
ElDatePicker, import('element-plus/es/components/button/style/css'),
ElDivider, ]).then(([res]) => res.ElButton),
ElInput, );
ElInputNumber, const ElCheckbox = defineAsyncComponent(() =>
ElNotification, Promise.all([
ElRadio, import('element-plus/es/components/checkbox/index'),
ElRadioButton, import('element-plus/es/components/checkbox/style/css'),
ElRadioGroup, ]).then(([res]) => res.ElCheckbox),
ElSelectV2, );
ElSpace, const ElCheckboxButton = defineAsyncComponent(() =>
ElSwitch, Promise.all([
ElTimePicker, import('element-plus/es/components/checkbox/index'),
ElTreeSelect, import('element-plus/es/components/checkbox-button/style/css'),
ElUpload, ]).then(([res]) => res.ElCheckboxButton),
} from 'element-plus'; );
const ElCheckboxGroup = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/checkbox/index'),
import('element-plus/es/components/checkbox-group/style/css'),
]).then(([res]) => res.ElCheckboxGroup),
);
const ElDatePicker = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/date-picker/index'),
import('element-plus/es/components/date-picker/style/css'),
]).then(([res]) => res.ElDatePicker),
);
const ElDivider = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/divider/index'),
import('element-plus/es/components/divider/style/css'),
]).then(([res]) => res.ElDivider),
);
const ElInput = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/input/index'),
import('element-plus/es/components/input/style/css'),
]).then(([res]) => res.ElInput),
);
const ElInputNumber = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/input-number/index'),
import('element-plus/es/components/input-number/style/css'),
]).then(([res]) => res.ElInputNumber),
);
const ElRadio = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/radio/index'),
import('element-plus/es/components/radio/style/css'),
]).then(([res]) => res.ElRadio),
);
const ElRadioButton = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/radio/index'),
import('element-plus/es/components/radio-button/style/css'),
]).then(([res]) => res.ElRadioButton),
);
const ElRadioGroup = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/radio/index'),
import('element-plus/es/components/radio-group/style/css'),
]).then(([res]) => res.ElRadioGroup),
);
const ElSelectV2 = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/select-v2/index'),
import('element-plus/es/components/select-v2/style/css'),
]).then(([res]) => res.ElSelectV2),
);
const ElSpace = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/space/index'),
import('element-plus/es/components/space/style/css'),
]).then(([res]) => res.ElSpace),
);
const ElSwitch = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/switch/index'),
import('element-plus/es/components/switch/style/css'),
]).then(([res]) => res.ElSwitch),
);
const ElTimePicker = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/time-picker/index'),
import('element-plus/es/components/time-picker/style/css'),
]).then(([res]) => res.ElTimePicker),
);
const ElTreeSelect = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/tree-select/index'),
import('element-plus/es/components/tree-select/style/css'),
]).then(([res]) => res.ElTreeSelect),
);
const ElUpload = defineAsyncComponent(() =>
Promise.all([
import('element-plus/es/components/upload/index'),
import('element-plus/es/components/upload/style/css'),
]).then(([res]) => res.ElUpload),
);
const withDefaultPlaceholder = <T extends Component>( const withDefaultPlaceholder = <T extends Component>(
component: T, component: T,

View File

@ -1,8 +1,7 @@
import { createApp, watchEffect } from 'vue'; import { createApp, watchEffect } from 'vue';
import { registerAccessDirective } from '@vben/access'; import { registerAccessDirective } from '@vben/access';
import { initTippy, registerLoadingDirective } from '@vben/common-ui'; import { registerLoadingDirective } from '@vben/common-ui';
import { MotionPlugin } from '@vben/plugins/motion';
import { preferences } from '@vben/preferences'; import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores'; import { initStores } from '@vben/stores';
import '@vben/styles'; import '@vben/styles';
@ -49,12 +48,14 @@ async function bootstrap(namespace: string) {
registerAccessDirective(app); registerAccessDirective(app);
// 初始化 tippy // 初始化 tippy
const { initTippy } = await import('@vben/common-ui/es/tippy');
initTippy(app); initTippy(app);
// 配置路由及路由守卫 // 配置路由及路由守卫
app.use(router); app.use(router);
// 配置Motion插件 // 配置Motion插件
const { MotionPlugin } = await import('@vben/plugins/motion');
app.use(MotionPlugin); app.use(MotionPlugin);
// 动态更新标题 // 动态更新标题

View File

@ -2,10 +2,10 @@ import type { RouteRecordRaw } from 'vue-router';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants'; import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { AuthPageLayout, BasicLayout } from '#/layouts';
import { $t } from '#/locales'; import { $t } from '#/locales';
import Login from '#/views/_core/authentication/login.vue';
const BasicLayout = () => import('#/layouts/basic.vue');
const AuthPageLayout = () => import('#/layouts/auth.vue');
/** 全局404页面 */ /** 全局404页面 */
const fallbackNotFoundRoute: RouteRecordRaw = { const fallbackNotFoundRoute: RouteRecordRaw = {
component: () => import('#/views/_core/fallback/not-found.vue'), component: () => import('#/views/_core/fallback/not-found.vue'),
@ -50,7 +50,7 @@ const coreRoutes: RouteRecordRaw[] = [
{ {
name: 'Login', name: 'Login',
path: 'login', path: 'login',
component: Login, component: () => import('#/views/_core/authentication/login.vue'),
meta: { meta: {
title: $t('page.auth.login'), title: $t('page.auth.login'),
}, },

View File

@ -8,32 +8,68 @@ import type { Component } from 'vue';
import type { BaseFormComponentType } from '@vben/common-ui'; import type { BaseFormComponentType } from '@vben/common-ui';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
import { defineComponent, getCurrentInstance, h, ref } from 'vue'; import {
defineAsyncComponent,
defineComponent,
getCurrentInstance,
h,
ref,
} from 'vue';
import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui'; import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
import {
NButton,
NCheckbox,
NCheckboxGroup,
NDatePicker,
NDivider,
NInput,
NInputNumber,
NRadio,
NRadioButton,
NRadioGroup,
NSelect,
NSpace,
NSwitch,
NTimePicker,
NTreeSelect,
NUpload,
} from 'naive-ui';
import { message } from '#/adapter/naive'; import { message } from '#/adapter/naive';
const NButton = defineAsyncComponent(() =>
import('naive-ui/es/button').then((res) => res.NButton),
);
const NCheckbox = defineAsyncComponent(() =>
import('naive-ui/es/checkbox').then((res) => res.NCheckbox),
);
const NCheckboxGroup = defineAsyncComponent(() =>
import('naive-ui/es/checkbox').then((res) => res.NCheckboxGroup),
);
const NDatePicker = defineAsyncComponent(() =>
import('naive-ui/es/date-picker').then((res) => res.NDatePicker),
);
const NDivider = defineAsyncComponent(() =>
import('naive-ui/es/divider').then((res) => res.NDivider),
);
const NInput = defineAsyncComponent(() =>
import('naive-ui/es/input').then((res) => res.NInput),
);
const NInputNumber = defineAsyncComponent(() =>
import('naive-ui/es/input-number').then((res) => res.NInputNumber),
);
const NRadio = defineAsyncComponent(() =>
import('naive-ui/es/radio').then((res) => res.NRadio),
);
const NRadioButton = defineAsyncComponent(() =>
import('naive-ui/es/radio').then((res) => res.NRadioButton),
);
const NRadioGroup = defineAsyncComponent(() =>
import('naive-ui/es/radio').then((res) => res.NRadioGroup),
);
const NSelect = defineAsyncComponent(() =>
import('naive-ui/es/select').then((res) => res.NSelect),
);
const NSpace = defineAsyncComponent(() =>
import('naive-ui/es/space').then((res) => res.NSpace),
);
const NSwitch = defineAsyncComponent(() =>
import('naive-ui/es/switch').then((res) => res.NSwitch),
);
const NTimePicker = defineAsyncComponent(() =>
import('naive-ui/es/time-picker').then((res) => res.NTimePicker),
);
const NTreeSelect = defineAsyncComponent(() =>
import('naive-ui/es/tree-select').then((res) => res.NTreeSelect),
);
const NUpload = defineAsyncComponent(() =>
import('naive-ui/es/upload').then((res) => res.NUpload),
);
const withDefaultPlaceholder = <T extends Component>( const withDefaultPlaceholder = <T extends Component>(
component: T, component: T,
type: 'input' | 'select', type: 'input' | 'select',

View File

@ -1,8 +1,7 @@
import { createApp, watchEffect } from 'vue'; import { createApp, watchEffect } from 'vue';
import { registerAccessDirective } from '@vben/access'; import { registerAccessDirective } from '@vben/access';
import { initTippy, registerLoadingDirective } from '@vben/common-ui'; import { registerLoadingDirective } from '@vben/common-ui';
import { MotionPlugin } from '@vben/plugins/motion';
import { preferences } from '@vben/preferences'; import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores'; import { initStores } from '@vben/stores';
import '@vben/styles'; import '@vben/styles';
@ -47,12 +46,14 @@ async function bootstrap(namespace: string) {
registerAccessDirective(app); registerAccessDirective(app);
// 初始化 tippy // 初始化 tippy
const { initTippy } = await import('@vben/common-ui/es/tippy');
initTippy(app); initTippy(app);
// 配置路由及路由守卫 // 配置路由及路由守卫
app.use(router); app.use(router);
// 配置Motion插件 // 配置Motion插件
const { MotionPlugin } = await import('@vben/plugins/motion');
app.use(MotionPlugin); app.use(MotionPlugin);
// 动态更新标题 // 动态更新标题

View File

@ -2,10 +2,10 @@ import type { RouteRecordRaw } from 'vue-router';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants'; import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { AuthPageLayout, BasicLayout } from '#/layouts';
import { $t } from '#/locales'; import { $t } from '#/locales';
import Login from '#/views/_core/authentication/login.vue';
const BasicLayout = () => import('#/layouts/basic.vue');
const AuthPageLayout = () => import('#/layouts/auth.vue');
/** 全局404页面 */ /** 全局404页面 */
const fallbackNotFoundRoute: RouteRecordRaw = { const fallbackNotFoundRoute: RouteRecordRaw = {
component: () => import('#/views/_core/fallback/not-found.vue'), component: () => import('#/views/_core/fallback/not-found.vue'),
@ -50,7 +50,7 @@ const coreRoutes: RouteRecordRaw[] = [
{ {
name: 'Login', name: 'Login',
path: 'login', path: 'login',
component: Login, component: () => import('#/views/_core/authentication/login.vue'),
meta: { meta: {
title: $t('page.auth.login'), title: $t('page.auth.login'),
}, },

View File

@ -17,6 +17,14 @@
".": { ".": {
"types": "./src/index.ts", "types": "./src/index.ts",
"default": "./src/index.ts" "default": "./src/index.ts"
},
"./es/tippy": {
"types": "./src/components/tippy/index.ts",
"default": "./src/components/tippy/index.ts"
},
"./es/loading": {
"types": "./src/components/loading/index.ts",
"default": "./src/components/loading/index.ts"
} }
}, },
"dependencies": { "dependencies": {

View File

@ -8,35 +8,64 @@ import type { Component } from 'vue';
import type { BaseFormComponentType } from '@vben/common-ui'; import type { BaseFormComponentType } from '@vben/common-ui';
import type { Recordable } from '@vben/types'; import type { Recordable } from '@vben/types';
import { defineComponent, getCurrentInstance, h, ref } from 'vue'; import {
defineAsyncComponent,
defineComponent,
getCurrentInstance,
h,
ref,
} from 'vue';
import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui'; import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
import { import { notification } from 'ant-design-vue';
AutoComplete,
Button, const AutoComplete = defineAsyncComponent(
Checkbox, () => import('ant-design-vue/es/auto-complete'),
CheckboxGroup, );
DatePicker, const Button = defineAsyncComponent(() => import('ant-design-vue/es/button'));
Divider, const Checkbox = defineAsyncComponent(
Input, () => import('ant-design-vue/es/checkbox'),
InputNumber, );
InputPassword, const CheckboxGroup = defineAsyncComponent(() =>
Mentions, import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup),
notification, );
Radio, const DatePicker = defineAsyncComponent(
RadioGroup, () => import('ant-design-vue/es/date-picker'),
RangePicker, );
Rate, const Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider'));
Select, const Input = defineAsyncComponent(() => import('ant-design-vue/es/input'));
Space, const InputNumber = defineAsyncComponent(
Switch, () => import('ant-design-vue/es/input-number'),
Textarea, );
TimePicker, const InputPassword = defineAsyncComponent(() =>
TreeSelect, import('ant-design-vue/es/input').then((res) => res.InputPassword),
Upload, );
} from 'ant-design-vue'; const Mentions = defineAsyncComponent(
() => import('ant-design-vue/es/mentions'),
);
const Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio'));
const RadioGroup = defineAsyncComponent(() =>
import('ant-design-vue/es/radio').then((res) => res.RadioGroup),
);
const RangePicker = defineAsyncComponent(() =>
import('ant-design-vue/es/date-picker').then((res) => res.RangePicker),
);
const Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate'));
const Select = defineAsyncComponent(() => import('ant-design-vue/es/select'));
const Space = defineAsyncComponent(() => import('ant-design-vue/es/space'));
const Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch'));
const Textarea = defineAsyncComponent(() =>
import('ant-design-vue/es/input').then((res) => res.Textarea),
);
const TimePicker = defineAsyncComponent(
() => import('ant-design-vue/es/time-picker'),
);
const TreeSelect = defineAsyncComponent(
() => import('ant-design-vue/es/tree-select'),
);
const Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload'));
const withDefaultPlaceholder = <T extends Component>( const withDefaultPlaceholder = <T extends Component>(
component: T, component: T,

View File

@ -1,14 +1,12 @@
import { createApp, watchEffect } from 'vue'; import { createApp, watchEffect } from 'vue';
import { registerAccessDirective } from '@vben/access'; import { registerAccessDirective } from '@vben/access';
import { initTippy, registerLoadingDirective } from '@vben/common-ui'; import { registerLoadingDirective } from '@vben/common-ui';
import { MotionPlugin } from '@vben/plugins/motion';
import { preferences } from '@vben/preferences'; import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores'; import { initStores } from '@vben/stores';
import '@vben/styles'; import '@vben/styles';
import '@vben/styles/antd'; import '@vben/styles/antd';
import { VueQueryPlugin } from '@tanstack/vue-query';
import { useTitle } from '@vueuse/core'; import { useTitle } from '@vueuse/core';
import { $t, setupI18n } from '#/locales'; import { $t, setupI18n } from '#/locales';
@ -21,13 +19,13 @@ async function bootstrap(namespace: string) {
// 初始化组件适配器 // 初始化组件适配器
await initComponentAdapter(); await initComponentAdapter();
// // 设置弹窗的默认配置 // 设置弹窗的默认配置
// setDefaultModalProps({ // setDefaultModalProps({
// fullscreenButton: false, // fullscreenButton: false,
// }); // });
// // 设置抽屉的默认配置 // 设置抽屉的默认配置
// setDefaultDrawerProps({ // setDefaultDrawerProps({
// // zIndex: 1020, // zIndex: 1020,
// }); // });
const app = createApp(App); const app = createApp(App);
@ -48,15 +46,18 @@ async function bootstrap(namespace: string) {
registerAccessDirective(app); registerAccessDirective(app);
// 初始化 tippy // 初始化 tippy
const { initTippy } = await import('@vben/common-ui/es/tippy');
initTippy(app); initTippy(app);
// 配置路由及路由守卫 // 配置路由及路由守卫
app.use(router); app.use(router);
// 配置@tanstack/vue-query // 配置@tanstack/vue-query
const { VueQueryPlugin } = await import('@tanstack/vue-query');
app.use(VueQueryPlugin); app.use(VueQueryPlugin);
// 配置Motion插件 // 配置Motion插件
const { MotionPlugin } = await import('@vben/plugins/motion');
app.use(MotionPlugin); app.use(MotionPlugin);
// 动态更新标题 // 动态更新标题

View File

@ -2,10 +2,10 @@ import type { RouteRecordRaw } from 'vue-router';
import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants'; import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
import { AuthPageLayout, BasicLayout } from '#/layouts';
import { $t } from '#/locales'; import { $t } from '#/locales';
import Login from '#/views/_core/authentication/login.vue';
const BasicLayout = () => import('#/layouts/basic.vue');
const AuthPageLayout = () => import('#/layouts/auth.vue');
/** 全局404页面 */ /** 全局404页面 */
const fallbackNotFoundRoute: RouteRecordRaw = { const fallbackNotFoundRoute: RouteRecordRaw = {
component: () => import('#/views/_core/fallback/not-found.vue'), component: () => import('#/views/_core/fallback/not-found.vue'),
@ -50,7 +50,7 @@ const coreRoutes: RouteRecordRaw[] = [
{ {
name: 'Login', name: 'Login',
path: 'login', path: 'login',
component: Login, component: () => import('#/views/_core/authentication/login.vue'),
meta: { meta: {
title: $t('page.auth.login'), title: $t('page.auth.login'),
}, },