路由懒加载

路由懒加载是一种按需加载组件的策略,只在用户访问对应路由时才加载组件代码,从而减小初始包体积、加快首屏加载速度。

使用 lazy 函数

vitarx-router 使用 vitarx 提供的 lazy 函数实现组件懒加载:

tsx
import { lazy } from 'vitarx'
import { createRouter } from 'vitarx-router'

const router = createRouter({
  routes: [
    {
      path: '/',
      component: Home // 同步加载
    },
    {
      path: '/user/{id}',
      component: lazy(() => import('./pages/User.tsx')) // 懒加载
    }
  ]
})

lazy(() => import(...)) 会将组件代码分离为独立的 chunk,仅在路由被访问时才加载。

命名视图懒加载

命名视图同样支持懒加载,每个视图可以独立配置:

tsx
const router = createRouter({
  routes: [
    {
      path: '/dashboard',
      component: {
        default: lazy(() => import('./pages/Dashboard.tsx')),
        sidebar: lazy(() => import('./pages/DashboardSidebar.tsx'))
      }
    }
  ]
})

文件路由的导入模式

使用文件路由时,可以通过 importMode 选项控制组件的导入方式:

‘lazy’(默认)

生成懒加载表达式,组件按需加载:

ts
// vite.config.ts
VitarxRouter({ importMode: 'lazy' })

// 生成的代码
const routes = [
  {
    path: '/about',
    component: lazy(() => import('/src/pages/about.tsx'))
  }
]

‘sync’

生成静态导入语句,组件在初始化时全部加载:

ts
// vite.config.ts
VitarxRouter({ importMode: 'sync' })

// 生成的代码
import About from '/src/pages/about.tsx'
const routes = [
  {
    path: '/about',
    component: About
  }
]

自定义函数

通过函数自定义导入逻辑,可以实现更灵活的加载策略:

ts
// vite.config.ts
VitarxRouter({
  importMode: context => {
    // 首页同步加载,其他页面懒加载
    if (context.filePath.endsWith('index.tsx')) {
      return 'sync'
    }
    return 'lazy'
  }
})

自定义函数的 context 参数包含:

ts
interface ImportModeContext {
  /** 组件文件路径(已 JSON.stringify) */
  importPath: string
  /** 组件文件原始路径 */
  filePath: string
  /** 添加导入语句到生成的代码顶部 */
  addImport: (statement: string) => void
}

预加载

router.resolveComponents() 方法可以预加载当前路由匹配到的所有异步组件:

ts
// 预加载当前路由的异步组件
await router.resolveComponents()

// 预加载指定路由的异步组件
const route = router.matchRoute({ index: '/user/123' })
if (route) {
  await router.resolveComponents(route)
}

INFO

resolveComponents 采用 allSettled 策略,即使部分组件加载失败也不会阻断路由导航。组件加载的具体错误应由视图层捕获和处理。

常见的预加载场景是在用户悬停链接时提前加载目标页面:

tsx
function prefetchRoute(path: string) {
  const route = router.matchRoute({ index: path })
  if (route) {
    router.resolveComponents(route)
  }
}

// 鼠标悬停时预加载
;<RouterLink to="/user/123" onMouseEnter={() => prefetchRoute('/user/123')}>
  用户详情
</RouterLink>

完整示例

ts
import { lazy } from 'vitarx'
import { createRouter } from 'vitarx-router'

const router = createRouter({
  routes: [
    // 首页同步加载
    { path: '/', component: Home },
    // 其他页面懒加载
    {
      path: '/about',
      component: lazy(() => import('./pages/About.tsx'))
    },
    {
      path: '/user/{id}',
      component: lazy(() => import('./pages/User.tsx'))
    },
    // 命名视图懒加载
    {
      path: '/dashboard',
      component: {
        default: lazy(() => import('./pages/Dashboard.tsx')),
        sidebar: lazy(() => import('./pages/DashboardSidebar.tsx'))
      }
    }
  ]
})