### Vue.js Suspense Data Fetching Example Source: https://uvr.esm.is/data-loaders/rfc Demonstrates data fetching using Vue's Suspense API within a component's setup function. This example shows how to fetch user list data and handle manual reloading. It also illustrates fetching user data based on route parameters and handling navigation updates. ```vue ``` ```vue ``` -------------------------------- ### Nested Routes Example (without parent component) Source: https://uvr.esm.is/guide/file-based-routing Illustrates the generated `routes` array when a parent folder exists but the corresponding parent `.vue` file does not. The route is created, but it lacks a component, serving solely as a container for its children. ```javascript const routes = [ { path: '/users', // notice how there is no component here children: [ { path: '', component: () => import('src/pages/users/index.vue') }, ], }, ] ``` -------------------------------- ### Typed useRoute() Examples (TypeScript) Source: https://uvr.esm.is/guide/typescript Demonstrates different ways to use the `useRoute()` function with type parameters to get typed route information, including narrowing down types and including child routes. It highlights the recommended approach for ease of use and completeness. ```typescript // ---cut-start--- import 'unplugin-vue-router/client' import './typed-router.d' import { useRoute, type RouteLocationNormalizedLoaded } from 'vue-router' // ---cut-end--- // @errors: 2322 2339 // @moduleResolution: bundler // These are all valid ways to get a typed route and return the // provided route's and any of its child routes' typings. // Note that `/users/[id]/edit` is a child route // of `/users/[id]` in this example. // Not recommended, since this leaves out any child routes' typings. const userRouteWithIdCasted = useRoute() as RouteLocationNormalizedLoaded<'/users/[id]'> userRouteWithIdCasted.params.id // Better way. Includes child routes' typings, but no autocompletion. const userRouteWithIdTypeParam = useRoute<'/users/[id]'>() userRouteWithIdTypeParam.params.id // ๐Ÿ‘‡ This one is the easiest to write because it both // autocompletes and includes child routes' typings. const userRouteWithIdParam = useRoute('/users/[id]') userRouteWithIdParam.name userRouteWithIdParam.params.id ``` -------------------------------- ### Route Manipulation with ViteSSG Source: https://uvr.esm.is/introduction This example shows how to manipulate routes when using ViteSSG, specifically integrating layout setup. It highlights the difference between using generated routes directly and applying layout configurations. Note that type support for manipulated routes might require build-time route configurations. ```ts import { ViteSSG } from 'vite-ssg' import { setupLayouts } from 'virtual:generated-layouts' import App from './App.vue' import type { UserModule } from './types' // import generatedRoutes from '~pages' // [!code --] import { routes } from 'vue-router/auto-routes' // [!code ++] import '@unocss/reset/tailwind.css' import './styles/main.css' import 'uno.css' // 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)) } ) ``` -------------------------------- ### Configure Multiple Routes Folders with Path Prefixes Source: https://uvr.esm.is/guide/file-based-routing Shows how to configure Vue Router to use multiple directories for routes. Each directory can have an optional path prefix, which can include parameters and does not need to start or end with a slash. ```typescript import VueRouter from 'unplugin-vue-router/vite' // ---cut--- // @moduleResolution: bundler VueRouter({ routesFolder: [ 'src/pages', { src: 'src/admin/routes', path: 'admin/', }, { src: 'src/docs', path: 'docs/:lang/', }, { src: 'src/promos', path: 'promos-' }, ], }) ``` -------------------------------- ### Vue.js Project Setup with Vue Router Source: https://uvr.esm.is/introduction This snippet demonstrates the basic setup for a Vue.js application using Vue Router. It involves creating a router instance with routes imported from `vue-router/auto-routes` and then using this router with the Vue app. Dependencies include `vue` and `vue-router`. ```ts import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import { routes } from 'vue-router/auto-routes' import App from './App.vue' const router = createRouter({ history: createWebHistory(), routes, }) createApp(App) .use(router) .mount('#app') ``` -------------------------------- ### Nested Routes Example (with parent component) Source: https://uvr.esm.is/guide/file-based-routing Demonstrates how a parent route is generated when both a parent folder and a `.vue` file with the same name exist. The child routes are nested within the parent's ``. This structure influences the generated `routes` array. ```javascript const routes = [ { path: '/users', component: () => import('src/pages/users.vue'), children: [ { path: '', component: () => import('src/pages/users/index.vue') }, ], }, ] ``` -------------------------------- ### Setup Nuxt Data Loader Plugin (TypeScript) Source: https://uvr.esm.is/data-loaders/nuxt This snippet demonstrates how to create a Nuxt plugin to initialize the DataLoaderPlugin. It requires the Vue Router instance and a boolean indicating server-side rendering. The plugin is placed in the `plugins` directory. ```typescript // plugins/data-loaders.ts import { DataLoaderPlugin } from 'unplugin-vue-router/data-loaders' export default defineNuxtPlugin({ name: 'data-loaders', dependsOn: ['nuxt:router'], setup(nuxtApp) { const appConfig = useAppConfig() nuxtApp.vueApp.use(DataLoaderPlugin, { router: nuxtApp.vueApp.config.globalProperties.$router, isSSR: import.meta.server, // other options... }) }, }) ``` -------------------------------- ### Configure Dynamic Routes with Parameters Source: https://uvr.esm.is/guide/file-based-routing Illustrates how to create dynamic routes in Vue Router by wrapping parameter names in brackets within filenames. Supports single, multiple, optional, and repeatable parameters, as well as catch-all routes. ```javascript // Single dynamic parameter // src/pages/users/[id].vue -> /users/:id // Multiple dynamic parameters // src/pages/product_[skuId]_[seoDescription].vue -> /product_:skuId_:seoDescription // Optional parameter // src/pages/users/[[id]].vue -> /users/:id? // Repeatable parameter // src/pages/articles/[slugs]+.vue -> /articles/:slugs+ // Optional repeatable parameter // src/pages/articles/[[slugs]]+.vue -> /articles/:slugs* // Catch all / 404 route // src/pages/[...path].vue -> /:path(.*) // src/pages/articles/[...path].vue -> /articles/:path(.*) ``` -------------------------------- ### Controlling Navigation with NavigationResult (TypeScript) Source: https://uvr.esm.is/data-loaders/rfc Illustrates how to control navigation flow within a data loader by returning a NavigationResult. This example shows how to redirect to a 'not-found' page for 404 errors or re-throw other errors to abort navigation. ```typescript import { NavigationResult } from 'vue-router' export const useUserData = defineLoader( async (to) => { try { const user = await getUserById(to.params.id) return user } catch (error) { if (error.status === 404) { return new NavigationResult({ name: 'not-found', params: { pathMatch: '' } }) ) } else { throw error // aborts the vue router navigation } } } ) ``` -------------------------------- ### Configure Vue Router with Data Loaders Source: https://uvr.esm.is/data-loaders/rfc This TypeScript example shows how to configure a Vue Router instance. It illustrates two ways to integrate data loaders: by specifying them in the `meta.loaders` array for non-lazy-loaded components, or by relying on automatically picked-up exported loaders from lazy-loaded components. ```typescript import './shims-vue.d' // ---cut--- // @moduleResolution: bundler import { createRouter, createWebHistory } from 'vue-router' import UserList from './pages/UserList.vue' // could be anywhere import { useUserList, useUserData, type User } from './loaders/users' export const router = createRouter({ history: createWebHistory(), routes: [ { path: '/users', component: UserList, meta: { // Required when the component is not lazy loaded loaders: [useUserList], }, }, { path: '/users/:id', // automatically picks up all exported loaders component: () => import('./pages/UserDetails.vue'), }, ], }) ``` -------------------------------- ### Define a Basic Data Loader Source: https://uvr.esm.is/data-loaders/rfc This example shows how to define a basic data loader using `defineLoader()`. It accepts a route path and an asynchronous function that fetches data based on route parameters. This function is designed to work independently of component instances and can utilize global injections like Pinia stores. ```typescript import 'unplugin-vue-router/client' import './typed-router.d' import { defineBasicLoader as defineLoader } from 'unplugin-vue-router/data-loaders/basic' // ---cut--- import { getUserById } from '../api' export const useUserData = defineLoader('/users/[id]', async (route) => { return getUserById(route.params.id) }) ``` -------------------------------- ### Vue Component with Loader Script (Vue/TypeScript) Source: https://uvr.esm.is/data-loaders/rfc Demonstrates a new ` ``` -------------------------------- ### Nested Routes with '.' as '/' Source: https://uvr.esm.is/guide/file-based-routing Shows how to create nested routes that do not affect the UI hierarchy by using a dot (`.`) in the filename, which is translated to a slash (`/`) in the generated route path. This is useful for adding routes like `/users/create` without nesting the component. ```javascript const routes = [ { path: '/users', component: () => import('src/pages/users.vue'), children: [ { path: '', component: () => import('src/pages/users/index.vue') }, { path: ':id', component: () => import('src/pages/users/[id].vue') }, ], }, { path: '/users/create', component: () => import('src/pages/users.create.vue'), }, ] ``` -------------------------------- ### Migrate to file-based routing Source: https://uvr.esm.is/introduction This example demonstrates migrating from a manually defined Vue Router configuration to Unplugin Vue Router's file-based routing. Components are moved and renamed to match the file structure. ```typescript import { createRouter, createWebHistory } from 'vue-router' import { routes, handleHotUpdate } from 'vue-router/auto-routes' // [!code ++] export const router = createRouter({ history: createWebHistory(), routes: [ // [!code --] { // [!code --] path: '/', // [!code --] component: () => import('src/pages/Home.vue'), // [!code --] }, // [!code --] { // [!code --] path: '/users/:id', // [!code --] component: () => import('src/pages/User.vue'), // [!code --] } // [!code --] { // [!code --] path: '/about', // [!code --] component: () => import('src/pages/About.vue'), // [!code --] }, // [!code --] ] // [!code --] routes, // [!code ++] }) // This will update routes at runtime without reloading the page if (import.meta.hot) { // [!code ++] handleHotUpdate(router) // [!code ++] } // [!code ++] ``` ```typescript import { createApp } from 'vue' import { router } from './router' import App from './App.vue' createApp(App).use(router).mount('#app') ``` -------------------------------- ### Add Runtime Routes with HMR in Vue Router Source: https://uvr.esm.is/guide/hmr This example shows how to add routes dynamically at runtime while HMR is enabled. The `handleHotUpdate` function can accept a callback that receives new routes. This ensures that new routes are correctly added during development. In production, routes are added directly. This is optional; you can also choose to reload the page. ```typescript import { createRouter, createWebHistory } from 'vue-router' import { routes, handleHotUpdate } from 'vue-router/auto-routes' export const router = createRouter({ history: createWebHistory(), routes, }) function addRedirects() { router.addRoute({ path: '/new-about', redirect: '/about?from=/new-about', }) } if (import.meta.hot) { handleHotUpdate(router, (newRoutes) => { addRedirects() }) } else { // production addRedirects() } ``` -------------------------------- ### Importing Client Types and Typed Routes Source: https://uvr.esm.is/guide/typescript This TypeScript snippet demonstrates the necessary imports to enable typed routing in your Vue application. It includes the client-side types from `unplugin-vue-router/client` and the generated typed routes from `./typed-router.d`. This setup allows `vue-router` to be aware of your application's route configuration. ```typescript // ---cut-start--- import 'unplugin-vue-router/client' import './typed-router.d' // ---cut-end--- // @moduleResolution: bundler import { useRouter, useRoute } from 'vue-router' const router = useRouter() router.push('') // ^| ``` -------------------------------- ### Install Unplugin Vue Router Source: https://uvr.esm.is/introduction Install the Unplugin Vue Router package as a development dependency using npm or yarn. This is the first step to integrate the plugin into your project. ```bash npm install -D unplugin-vue-router ``` -------------------------------- ### Setup DataLoaderPlugin with Vue Router Source: https://uvr.esm.is/data-loaders/rfc This snippet demonstrates how to integrate the DataLoaderPlugin into a Vue application. It requires the Vue Router instance and should be used before the router itself to ensure proper navigation guard attachment. The plugin facilitates data loading alongside route navigation. ```typescript import { createApp } from 'vue' import { createRouter } from 'vue-router' import { DataLoaderPlugin } from 'unplugin-vue-router/data-loaders' const router = createRouter({ // ... }) const app = createApp(App) app.use(DataLoaderPlugin, { router }) // add the router after the DataLoaderPlugin app.use(router) ``` -------------------------------- ### Configure Custom File Extensions for Pages Source: https://uvr.esm.is/guide/file-based-routing Explains how to configure Vue Router to recognize custom file extensions (e.g., '.md') as page components. This can be set globally or overridden for specific route folders. ```typescript import VueRouter from 'unplugin-vue-router/vite' // ---cut--- // @moduleResolution: bundler VueRouter({ extensions: ['.vue', '.md'], routesFolder: [ 'src/pages', { src: 'src/docs', extensions: ['.md'], }, ], }) ``` -------------------------------- ### Install DataLoaderPlugin - TypeScript Source: https://uvr.esm.is/data-loaders Installs and configures the DataLoaderPlugin for Vue Router. This plugin should be registered before the router instance to ensure proper initialization for data loading functionalities. ```typescript import 'unplugin-vue-router/client' import './typed-router.d' // @moduleResolution: bundler // --- import { createApp } from 'vue' import { routes } from 'vue-router/auto-routes' import { createRouter, createWebHistory } from 'vue-router' import { DataLoaderPlugin } from 'unplugin-vue-router/data-loaders' const router = createRouter({ history: createWebHistory(), routes, }) const app = createApp({}) // Register the plugin before the router app.use(DataLoaderPlugin, { router }) // adding the router will trigger the initial navigation app.use(router) app.mount('#app') ``` -------------------------------- ### Data Loaders with AbortSignal for Request Cancellation Source: https://uvr.esm.is/data-loaders/rfc This TypeScript example demonstrates how data loaders can accept an `AbortSignal` in their arguments. This signal can be passed to `fetch` or other Web APIs, allowing requests to be automatically cancelled if the navigation is cancelled or aborted. This aligns with the Navigation API for cancellation. ```typescript import { defineBasicLoader as defineLoader } from 'unplugin-vue-router/data-loaders/basic' interface Book { title: string isbn: string description: string } function fetchBookCollection(options: { signal?: AbortSignal }): Promise { return {} as any } // ---cut--- export const useBookCollection = defineLoader(async (_route, { signal }) => { return fetchBookCollection({ signal }) }) ``` -------------------------------- ### Non-Blocking Data Fetching with Lazy Loaders Source: https://uvr.esm.is/data-loaders/rfc This example shows how to configure data loaders to be 'lazy', preventing them from blocking navigation. This is useful for non-critical data fetching, allowing the page to display earlier while background data is fetched. The `isLoading` property can be used to show loading indicators. ```vue ``` -------------------------------- ### Renaming Data Property from UserData Loader Source: https://uvr.esm.is/data-loaders/rfc Shows a practical example of renaming the 'data' property returned by `useUserData` to a more descriptive name, such as 'user', for better code readability and maintainability. ```typescript import 'unplugin-vue-router/client' import './typed-router.d' import { useUserData } from './loaders/users' // ---cut--- const { data: user } = useUserData() ``` -------------------------------- ### Define Named Views in Vue Router Source: https://uvr.esm.is/guide/file-based-routing Demonstrates how to define named views in Vue Router by appending '@' to filenames. This allows for multiple views within a single route. The default name for a non-named view is 'default'. ```javascript { path: '/', component: { aux: () => import('src/pages/index@aux.vue') } } ``` -------------------------------- ### Nested Loaders and Shared Data Fetching in Vue Router Source: https://uvr.esm.is/data-loaders/rfc Illustrates how to define multiple loaders, including nested dependencies, ensuring data is fetched only once and shared across loaders. This setup handles complex scenarios where loaders might be exported and used by multiple other loaders, simplifying data management without manual optimization. ```typescript import 'unplugin-vue-router/client' import './typed-router.d' import { defineBasicLoader as defineLoader } from 'unplugin-vue-router/data-loaders/basic' // ---cut--- import { getFriends, getCommonFriends, getUserById, getCurrentUser, } from './api' export const useUserData = defineLoader('/users/[id]', async (route) => { return getUserById(route.params.id) }) export const useCurrentUserData = defineLoader('/users/[id]', async (route) => { const me = await getCurrentUser() // imagine legacy APIs that cannot be grouped into one single fetch const friends = await getFriends(me.id) return { ...me, friends } }) export const useUserCommonFriends = defineLoader( '/users/[id]', async (route) => { const user = await useUserData() const me = await useCurrentUserData() const friends = await getCommonFriends(user.id, me.id) return { ...me, commonFriends: { with: user, friends } } } ) ``` -------------------------------- ### Select Navigation Result with DataLoaderPlugin Source: https://uvr.esm.is/data-loaders/rfc Configures the DataLoaderPlugin to manually select a navigation result when multiple loaders return different outcomes. This is useful for prioritizing specific results, like a 'not-found' route, over others. It's configured via the `selectNavigationResult` option in the plugin setup. ```typescript import 'unplugin-vue-router/client' import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import { DataLoaderPlugin } from 'unplugin-vue-router/data-loaders' const app = createApp({}) const router = createRouter({ history: createWebHistory(), routes: [], }) // ---cut--- // @moduleResolution: bundler // @noErrors app.use(DataLoaderPlugin, { router, selectNavigationResult(results) { for (const { value } of results) { if ( typeof value === 'object' && 'name' in value && value.name === 'not-found' ) { return value } } }, }) ``` -------------------------------- ### Configure sfc-typed-router Plugin in Nuxt (nuxt.config.ts) Source: https://uvr.esm.is/guide/typescript Manual configuration for the `sfc-typed-router` Volar plugin within a Nuxt project if it's not enabled by default. This ensures automatic typing of `useRoute()` and `$route` in page components. ```typescript export default defineNuxtConfig({ // ... typescript: { tsConfig: { vueCompilerOptions: { plugins: ['unplugin-vue-router/volar/sfc-typed-router'], }, }, }, }) ``` -------------------------------- ### Define and Export Basic Data Loader in Vue Component Source: https://uvr.esm.is/data-loaders/rfc This snippet demonstrates how to define a data loader using `defineBasicLoader` within a Vue component's script. The loader is exported and can be used within the component's setup script to fetch data based on route parameters. It exposes reactive properties like `data`, `isLoading`, and `error`, along with a `reload` function. ```vue ``` -------------------------------- ### Implement Data Loader Cancellation with AbortSignal Source: https://uvr.esm.is/data-loaders/load-cancellation This example demonstrates how to define a basic data loader using `defineBasicLoader` from `unplugin-vue-router/data-loaders/basic`. It accepts an `AbortSignal` which is passed to an asynchronous `fetchBookCollection` function. This allows ongoing requests to be cancelled if the navigation is aborted, preventing unnecessary network activity and resource consumption. ```typescript interface Book { title: string isbn: string description: string } function fetchBookCollection(options: { signal?: AbortSignal }): Promise { return {} as any } // ---cut--- import { defineBasicLoader } from 'unplugin-vue-router/data-loaders/basic' export const useBookCollection = defineBasicLoader( async (_route, { signal }) => { return fetchBookCollection({ signal }) } ) ``` -------------------------------- ### Configure Expected Errors Globally with DataLoaderPlugin Source: https://uvr.esm.is/data-loaders/error-handling This example shows how to set up expected errors globally for all data loaders using the `DataLoaderPlugin`. By passing an array of error classes to the `errors` option in the plugin configuration, these errors will be treated as expected across the application. This requires Vue Router's `router` instance to be provided. ```typescript import 'unplugin-vue-router/client' import './typed-router.d' import { createApp } from 'vue' import { DataLoaderPlugin } from 'unplugin-vue-router/data-loaders' const app = createApp({}) const router = {} as any class MyError extends Error { name = 'MyError' constructor(message: string) { super(message) } } // @moduleResolution: bundler // ---cut--- app.use(DataLoaderPlugin, { router, // checks with `instanceof MyError` errors: [MyError], }) ``` -------------------------------- ### Define and Use Basic Loader - Vue Single File Component Source: https://uvr.esm.is/data-loaders Defines a basic data loader using `defineBasicLoader` and demonstrates its usage within a Vue component's setup. It fetches user data based on the route parameters and handles loading, error, and data states. ```vue ``` -------------------------------- ### Using UserData Loader Composable Source: https://uvr.esm.is/data-loaders/rfc Demonstrates how to import and use the `useUserData` composable, which returns data, loading, error states, and a reload function. It highlights the types of these properties for effective data fetching and management. ```typescript import 'unplugin-vue-router/client' import './typed-router.d' import { useUserData } from './loaders/users' // ---cut--- const { // hover over each property to see the type data, isLoading, error, reload, } = useUserData() ``` -------------------------------- ### Defining a Data Loader with Immediate Commit Source: https://uvr.esm.is/data-loaders/rfc Demonstrates setting the 'commit' option to 'immediate' for a data loader. This ensures that the loader's state is reflected immediately in the data and error properties, rather than waiting for all loaders to resolve. ```typescript import { defineBasicLoader as defineLoader } from 'unplugin-vue-router/data-loaders/basic' interface Book { title: string isbn: string description: string } function fetchBookCollection(): Promise { return {} as any } // ---cut--- export const useBookCollection = defineLoader(fetchBookCollection, { commit: 'immediate', }) ``` -------------------------------- ### Augment RouteNamedMap for Dynamic Routes (TypeScript) Source: https://uvr.esm.is/guide/typescript Augment the `RouteNamedMap` interface to add types for dynamic routes that are added during runtime. This allows for type-safe access to these routes and their parameters. ```typescript import type { RouteNamedMap } from 'vue-router/auto-routes' export {} // needed in .d.ts files declare module 'vue-router/auto-routes' { import type { RouteRecordInfo, ParamValue, ParamValueOneOrMore, ParamValueZeroOrMore, ParamValueZeroOrOne, } from 'vue-router' export interface RouteNamedMap { // the key is the name and should match the first generic of RouteRecordInfo 'custom-dynamic-name': RouteRecordInfo< 'custom-dynamic-name', '/added-during-runtime/[...path]', // these are the raw param types (accept numbers, strings, booleans, etc) { path: ParamValue }, // these are the normalized params as found in useRoute().params { path: ParamValue }, // this is a union of all children route names // if the route does not have nested routes, pass `never` or omit this generic entirely 'custom-dynamic-child-name' > 'custom-dynamic-child-name': RouteRecordInfo< 'custom-dynamic-child-name', '/added-during-runtime/[...path]/child', { path: ParamValue }, { path: ParamValue }, never > } export interface _RouteFileInfoMap { // the key is the file path and should match the page component's file path '/added-during-runtime/[...path].vue': { // these are the route names that can be displayed within this component routes: 'custom-dynamic-name' | 'custom-dynamic-child-name' // these are the views that can be used in this file views: 'default' } '/added-during-runtime/[...path]/child.vue': { routes: 'custom-dynamic-child-name' views: never } } } ``` -------------------------------- ### Sequential Data Fetching with Vue Router Loaders Source: https://uvr.esm.is/data-loaders/rfc Demonstrates how to call and await one loader within another for sequential data fetching. Loaders imported and awaited inside other loaders will only be fetched once per navigation, even if called multiple times. This requires the nested loader to return a promise, often achieved by using a specific version of the loader composable. ```typescript import 'unplugin-vue-router/client' import './typed-router.d' import { defineBasicLoader as defineLoader } from 'unplugin-vue-router/data-loaders/basic' // ---cut--- // import the loader for user information import { useUserData } from './loaders/users' import { getCommonFriends, getCurrentUser } from './api' export const useUserCommonFriends = defineLoader(async (route) => { // loaders must be awaited inside other loaders // . โคต const user = await useUserData() // magically works const me = await getCurrentUser() // fetch other data const commonFriends = await getCommonFriends(me.id, user.id) return { ...user, commonFriends } }) ``` -------------------------------- ### Configure sfc-typed-router Volar Plugin (tsconfig.json) Source: https://uvr.esm.is/guide/typescript Configuration snippet for `tsconfig.json` to enable the `sfc-typed-router` Volar plugin. This plugin automatically types `useRoute()` and `$route` in page components, reducing boilerplate code. ```json { "compilerOptions": { // needed for the plugin to correctly resolve paths "rootDir": "." // ... }, // ... "vueCompilerOptions": { "plugins": ["unplugin-vue-router/volar/sfc-typed-router"] } } ``` -------------------------------- ### Configure tsconfig.json for Typed Routes Source: https://uvr.esm.is/guide/typescript This snippet shows how to include the generated `typed-router.d.ts` file in your `tsconfig.json` or `jsconfig.json` to enable type checking for your routes. Ensure the file is listed in the `include` or `files` property. ```json { // ... "include": [ /* ... */ "./typed-router.d.ts" ] // ... } ``` -------------------------------- ### Define SSR Loader with Key (TypeScript) Source: https://uvr.esm.is/data-loaders/rfc Demonstrates defining a data loader for SSR purposes, specifying a unique key for serialization. This allows the data loaded on the server to be passed to the client efficiently. ```typescript export const useBookCollection = defineLoader( async () => { const books = await fetchBookCollection() return books }, { key: 'bookCollection' } ) ``` -------------------------------- ### Define Single-Line Data Loader with Type Inference Source: https://uvr.esm.is/data-loaders/rfc This snippet demonstrates the simplest way to define a data loader using `defineBasicLoader`. It takes a function that fetches data and automatically infers the types. The resulting composable (`useBookCollection`) can then be used to access the fetched data reactively. ```typescript import { defineBasicLoader as defineLoader } from 'unplugin-vue-router/data-loaders/basic' interface Book { title: string isbn: string description: string } function fetchBookCollection(): Promise { return {} as any } // ---cut--- export const useBookCollection = defineLoader(fetchBookCollection) const { data } = useBookCollection() ``` -------------------------------- ### Integrate Layouts with Runtime Routes Source: https://uvr.esm.is/guide/extending-routes Configure Vue Router at runtime to integrate with layout systems like `vite-plugin-vue-layouts`. The `setupLayouts` function processes the routes array to apply layout configurations, ensuring proper rendering of nested views within designated layouts. This method is necessary when the layout plugin cannot be configured at build time. ```typescript import { createRouter } from 'vue-router' import { routes } from 'vue-router/auto-routes' import { setupLayouts } from 'virtual:generated-layouts' const router = createRouter({ // ... routes: setupLayouts(routes), }) ``` -------------------------------- ### TypeScript Data Loaders with Route Type Hinting Source: https://uvr.esm.is/data-loaders/rfc This snippet demonstrates how to use TypeScript with `unplugin-vue-router` to automatically generate types for routes. `defineLoader` infers return types and allows referencing route names for type hinting. It's intended for use in Vue.js projects with Vue Router. ```vue ``` -------------------------------- ### Add client-side types to env.d.ts Source: https://uvr.esm.is/introduction If you have an `env.d.ts` file, add a reference type for `unplugin-vue-router/client` to enable client-side type checking and autocompletion. ```typescript /// /// ``` -------------------------------- ### Configure Lazy Data Loading in Vue Source: https://uvr.esm.is/data-loaders/defining-loaders Demonstrates how to configure a data loader to be 'lazy', preventing it from blocking navigation. It shows how to access loading states and errors, and provides examples for conditional lazy loading during SSR and based on route changes. ```vue ``` ```typescript export const useUserData = defineBasicLoader( async (to) => { // ... }, { lazy: !import.meta.env.SSR, // Vite specific } ) ``` ```typescript export const useSearchResults = defineBasicLoader( async (to) => { // ... }, { // lazy if we are on staying on the same route lazy: (to, from) => to.name === from.name, } ) ``` -------------------------------- ### Define Multiple Nested Loaders with Shared Data Source: https://uvr.esm.is/data-loaders/nested-loaders Demonstrates defining multiple basic loaders (`useUserData`, `useCurrentUserData`, `useUserCommonFriends`) where `useUserCommonFriends` depends on the other two. This setup ensures that even complex dependencies are handled efficiently, with data fetched only once and shared across loaders. ```typescript import 'unplugin-vue-router/client' import './typed-router.d' import { defineBasicLoader } from 'unplugin-vue-router/data-loaders/basic' // ---cut--- import { getFriends, getCommonFriends, getUserById, getCurrentUser, } from './api' export const useUserData = defineBasicLoader('/users/[id]', async (route) => { return getUserById(route.params.id) }) export const useCurrentUserData = defineBasicLoader( '/users/[id]', async (route) => { const me = await getCurrentUser() // imagine legacy APIs that cannot be grouped into one single fetch const friends = await getFriends(me.id) return { ...me, friends } } ) export const useUserCommonFriends = defineBasicLoader( '/users/[id]', async (route) => { const user = await useUserData() const me = await useCurrentUserData() const friends = await getCommonFriends(user.id, me.id) return { ...me, commonFriends: { with: user, friends } } } ) ``` -------------------------------- ### Define Basic Data Loader with User Data Fetching (Vue) Source: https://uvr.esm.is/data-loaders/defining-loaders Demonstrates defining a basic data loader using `defineBasicLoader`. It fetches user data by ID based on the route parameters. The composable returned provides `data`, `isLoading`, `error`, and `reload` properties. This is specific to Vue's composition API. ```vue ``` -------------------------------- ### Define and Export Loaders Separately Source: https://uvr.esm.is/data-loaders/rfc Demonstrates defining data loaders in a separate file (e.g., `src/loaders/user.ts`) and exporting them for use in page components or other parts of the application. This promotes modularity and reusability of loader logic across different routes and components. ```typescript // src/loaders/user.ts export const useUserData = defineLoader(...) // ... ``` ```vue ``` ```vue ``` -------------------------------- ### Define Pinia Colada Loader with Vue Router Source: https://uvr.esm.is/data-loaders/colada Demonstrates how to define a data loader using `defineColadaLoader` from `unplugin-vue-router/data-loaders/pinia-colada`. This setup allows for asynchronous data fetching with caching, SSR support, and efficient state management, directly integrating with Vue Router's navigation. ```vue ``` -------------------------------- ### Define Basic Vue Router Data Loader Source: https://uvr.esm.is/data-loaders/basic Sets up a basic data loader using `defineBasicLoader` from `unplugin-vue-router/data-loaders/basic`. This function accepts a loader function that fetches data (e.g., user by ID) and an optional configuration object for SSR. It's designed to rerun on route navigation. Dependencies include `unplugin-vue-router/data-loaders/basic` and a custom API function like `getUserById`. ```vue ```