unplugin-vue-router

repository·main·Indexed 25 days ago

https://github.com/posva/unplugin-vue-router

A plugin providing automatic, file-based typed routing for Vue Router (version 4.4.0 or higher) with full TypeScript support. It generates typed routes based on file structure and includes features like the definePage macro and experimental data loaders via defineBasicLoader() and defineColadaLoader() for asynchronous state management and data fetching.

Tokens
24.2K
Snippets
75
Records
110
Agent score
80%

What's inside unplugin-vue-router

  1. Understand File-Based Routing basics

    main

    The plugin automatically generates a Vue Router configuration based on your file structure in src/pages (by default). Instead of manually maintaining a routes array, you simply add .vue files to your routes folder.

    Default behavior:

    • src/pages/index.vue -> /
    • src/pages/about.vue -> /about
    • src/pages/users/index.vue -> /users
    • src/pages/users/[id].vue -> /users/:id (where id is a route param).
    src/pages/
    ├── index.vue
    ├── about.vue
    └── users/
        ├── index.vue
        └── [id].vue
  2. Handle nested loader invalidation

    main

    If a parent loader calls a nested loader, the invalidation of the nested loader will automatically trigger an invalidation of the parent loader. This behavior depends on the specific loader implementation but is a common pattern for maintaining data consistency.

    Warning: Avoid circular dependencies where two loaders call each other, as this will create a dead lock.

  3. Determine error handling priority

    main

    When both global and local error handling configurations are present, local configuration takes priority. The logic follows this hierarchy:

    1. If local errors is false: The navigation is aborted. The data property is guaranteed not to be undefined (because the component won't render if navigation fails).
    2. If local errors is true: The loader relies on the globally defined errors option in DataLoaderPlugin. The data property may be undefined if an error occurs.
    3. Otherwise (else): The loader relies on the local errors option provided. The data property may be undefined if an error occurs.
  4. Understand route tracking in Colada loaders

    main

    The query function automatically tracks which properties of the to parameter are used. The loader will only trigger a refresh if a tracked property changes.

    For example, if your query function uses to.params.id, the loader will only refresh when the id parameter changes. Changes to to.query, to.hash, or other unused to.params will not trigger a refresh. If you need the data to update when these other properties change, you must configure the staleTime option.

  5. Understand the implications of reloading data

    main

    When using the reload method instead of a standard navigation, be aware of the following behaviors:

    Since the reload occurs outside of a formal navigation cycle:

    • Navigation guards (such as beforeRouteUpdate, beforeRouteLeave, etc.) will not run.
    • Any NavigationResult returned or thrown by the data loader will be ignored.

    Error Handling

    Because the reload is not part of a navigation, errors are not thrown in the traditional sense. Instead, errors encountered during a reload are captured and stored in the error property of the loader (similar to how lazy loaders behave). You should check this error property to display error states to the user during a reload attempt.

  6. How loaders work with nested routes

    main

    When working with nested routes, the loader management is automatically optimized. You do not need to manually export the loader in both the parent and the child components; the loader is shared between them automatically.

    Best Practice: For nested routes, it is simplest to always export data loaders in the page component where they are used.

  7. How Data Loaders work

    main

    Data Loaders extract asynchronous state management (like data fetching) outside of the component setup lifecycle.

    Unlike <Suspense>, which handles loading within the component tree, Data Loaders are automatically collected and awaited within a navigation guard. This ensures that data is fetched and ready before the component is even rendered, preventing

  8. Use Route Groups to organize files without affecting URLs

    main

    Route groups allow you to organize files into logical directories (e.g., for shared layouts) without adding those directory names to the URL path. Wrap the folder name in parentheses () to create a group.

    Example:

    • src/pages/(admin)/dashboard.vue -> /dashboard
    • src/pages/(user)/profile.vue -> /profile

    You can also use route groups in page components by naming them (name).vue inside a folder to act as the index.vue for that route.

    src/pages/
    ├── (admin)/
    │   ├── dashboard.vue
    │   └── settings.vue
    └── (user)/
       ├── profile.vue
       └── order.vue
  9. Understand the generated Route Map types

    main

    The plugin generates a RouteNamedMap interface which contains all route records in your application. Each record includes the route's name, path, typed parameters, and a list of its child route names. This map is consumed by unplugin-vue-router/client to configure vue-router types.

    Note: Types prefixed with an underscore (e.g., _RouteFileInfoMap) are used internally by the sfc-typed-router Volar plugin and should not be used directly.

  10. Manipulate routes with unplugin-vue-router

    main

    You can pass the routes to plugins (like layout generators) to modify them. However, note that manual manipulations of the routes object will not be reflected in the generated types.

    If you need type safety for your modified routes, use build-time routes instead.

    Example of using setupLayouts with generated routes:

    import { ViteSSG } from 'vite-ssg'
    import { setupLayouts } from 'virtual:generated-layouts'
    import App from './App.vue'
    import { routes } from 'vue-router/auto-routes'
    
    export const createApp = ViteSSG(
      App,
      {
        routes: setupLayouts(routes),
        base: import.meta.env.BASE_URL,
      },
      (ctx) => { /* ... */ }
    )
    import { ViteSSG } from 'vite-ssg'
    import { setupLayouts } from 'virtual:generated-layouts'
    import App from './App.vue'
    import generatedRoutes from '~pages' // [!code --]
    import { routes } from 'vue-router/auto-routes' // [!code ++]
    
    const routes = setupLayouts(generatedRoutes) // [!code --]
    
    // https://github.com/antfu/vite-ssg
    export const createApp = ViteSSG(
      App,
      {
        routes, // [!code --]
        routes: setupLayouts(routes), // [!code ++]
        base: import.meta.env.BASE_URL,
      },
      (ctx) => {
        // install all modules under `modules/`
        Object.values(
          import.meta.glob<{ install: UserModule }>('./modules/*.ts', {
            eager: true,
          })
        ).forEach((i) => i.install?.(ctx))
      }
    )
  11. Understand default error behavior in Data Loaders

    main

    By default, all errors thrown in a loader are treated as unexpected errors. This causes the navigation to abort (similar to a navigation guard), meaning the error will not be available in the loader's error property. Instead, these errors are intercepted by Vue Router's global error handler via router.onError().

    Exception: If the loader is not navigation-aware (such as lazy loaders or when reloading data), the error cannot be intercepted by Vue Router and will instead be kept in the loader's error property.