Skip to content

Commit

Permalink
refactor(data-loaders)!: rewrite of data loaders
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Data Loaders have been redesigned to be more flexible
and account for other libraries. Notably, the caching behavior has been
moved out of the basic loader to an extended one and the basic loader
has no cache. All of the pending bugs have also been fixed.
I recommend you to give the RFC examples a new read to get
setup: https://uvr.esm.is/rfcs/data-loaders/. Most of the changes are
simplifying things by removing them.
Here is a list of the breaking changes to simplify
migration:

- The `dataFetching` option is no longer needed.
- Manual work needed to add loaders with `HasDataLoaderMeta` has been
  removed. It is just no longer needed. Loaders are picked up from lazy
  loaded components and must otherwise be directly added to a `meta.loaders`
  array. See the example at https://uvr.esm.is/rfcs/data-loaders/#basic-example
- The function `setupDataFetchingGuard` has been replaced with a Vue
  Plugin. See https://uvr.esm.is/rfcs/data-loaders/#data-loader-setup
  for details.
- If you were relying on `cacheTime`, use the `staleTime` option in the
  new [`defineColadaLoader()`](https://uvr.esm.is/rfcs/data-loaders/colada) based off [@pinia/colada](https://github.com/posva/pinia-colada)
- To reduce the dependency on file-based router, things have been
  refactored and none of the defineLoader functions are automatically
  imported anymore. You can add them yourself to the list of auto
  imports, or import them from `vue-router/auto`. The good news is you
  no longer need to use the plugin in order to benefit from the data
  loaders; they can be directly imported from
  `unplugin-vue-router/runtime`.

If you find missing information or improvements, please open a Pull
Request to improve the `CHANGELOG.md`.
  • Loading branch information
posva committed Feb 15, 2024
1 parent 0873b94 commit f0b7b58
Show file tree
Hide file tree
Showing 20 changed files with 33 additions and 1,910 deletions.
9 changes: 4 additions & 5 deletions client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,12 @@ declare module 'vue-router/auto' {
options: _RouterOptions
): _RouterTyped<RouteNamedMap>

// Experimental Data Fetching
export {
// Experimental Data Fetching
definePage,
DataLoaderPlugin,
// FIXME: remove these in next major
_HasDataLoaderMeta as HasDataLoaderMeta,
_setupDataFetchingGuard as setupDataFetchingGuard,
_stopDataFetchingScope as stopDataFetchingScope,
defineBasicLoader,
defineColadaLoader,
NavigationResult,
} from 'unplugin-vue-router/runtime'
}
6 changes: 6 additions & 0 deletions docs/rfcs/data-loaders/basic.md
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
# `defineBasicLoader()`

## Setup

## Example

## SSR
10 changes: 9 additions & 1 deletion docs/rfcs/data-loaders/colada.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

Loaders that use [@pinia/colada](https://github.com/posva/pinia-colada) under the hood. These loaders provide a more efficient way to have asynchronous state with cache, ssr support and more.

The key used in these loaders are directly passed to `useQuery()` from `@pinia/colada` and are therefore invalidated by `useMutation()` calls.

## Setup

Follow the instructions in [@pinia/colada](https://github.com/posva/pinia-colada).

## Example

```vue
<script lang="ts">
import { defineColadaLoader } from 'unplugin-vue-router/runtime'
Expand Down Expand Up @@ -76,7 +84,7 @@ export const useUserData = defineColadaLoader('/users/[id]', {

## Refresh by default

To avoid unnecesarry frequent refreshes, Pinia Colada refreshes the data when navigating (instead of _refetching_). Change the `staleTime` option to control how often the data should be refreshed, e.g. setting it to 0 will refresh the data every time the route changes.
To avoid unnecessary frequent refreshes, Pinia Colada refreshes the data when navigating (instead of _refetching_). Change the `staleTime` option to control how often the data should be refreshed, e.g. setting it to 0 will refresh the data every time the route changes.

## Route tracking

Expand Down
18 changes: 2 additions & 16 deletions examples/nuxt/plugins/vueRouter.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
import { _setupDataFetchingGuard } from 'unplugin-vue-router/runtime'
import { DataLoaderPlugin } from 'unplugin-vue-router/runtime'

export default defineNuxtPlugin((nuxtApp) => {
// console.log('going in!', useRouter())
const data = _setupDataFetchingGuard(
useRouter(),
process.client ? nuxtApp.payload._uvr : undefined
)

if (process.server) {
nuxtApp.payload._uvr = data
}

useRouter()
.isReady()
.then(() => {
console.log('READY!', nuxtApp.payload._uvr)
})
// TODO:
})
12 changes: 6 additions & 6 deletions playground/src/pages/users/[id].vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<script lang="ts">
import { defineColadaLoader } from 'unplugin-vue-router/runtime'
export const myExport = 'OUTSIDE SETUP TEST'
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
export const useOldData = defineLoader(
'/users/[id]',
async (route) => {
console.log('useOldData', route)
export const useOldData = defineColadaLoader('/users/[id]', {
async query(route) {
return {
when: new Date(),
// if the id is not used, this data is cached forever
id: route.params.id,
}
},
{ key: 'old-user-id', cacheTime: 5000 }
)
key: (to) => ['user-id', to.params.id],
staleTime: 5000,
})
// NOTE: it's a bit different from the one in /[name].vue
export const useUserData = defineBasicLoader(
Expand Down
24 changes: 1 addition & 23 deletions src/codegen/generateRouteRecords.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,35 +152,13 @@ function generatePageImport(
return importName
}

function generateImportList(node: TreeNode, indentStr: string) {
const files = Array.from(node.value.components)

return `[
${files
.map(([_key, path]) => `${indentStr} () => import('${path}')`)
.join(',\n')}
${indentStr}]`
}

const LOADER_GUARD_RE = /['"]_loaderGuard['"]:.*$/

function formatMeta(node: TreeNode, indent: string): string {
const meta = node.meta
const formatted =
meta &&
meta
.split('\n')
.map(
// FIXME: remove after deprecated defineLoader is removed
(line) =>
indent +
line.replace(
LOADER_GUARD_RE,
'[_HasDataLoaderMeta]: ' +
generateImportList(node, indent + ' ') +
','
)
)
.map((line) => indent + line)
.join('\n')

return formatted ? '\n' + indent + 'meta: ' + formatted.trimStart() : ''
Expand Down
8 changes: 2 additions & 6 deletions src/codegen/vueRouterModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,12 @@ import { createRouter as _createRouter } from 'vue-router'
export * from 'vue-router'
export {
// NOTE: deprecated
_HasDataLoaderMeta as HasDataLoaderMeta,
_setupDataFetchingGuard as setupDataFetchingGuard,
_stopDataFetchingScope as stopDataFetchingScope,
definePage,
// new data fetching
DataLoaderPlugin,
defineBasicLoader,
defineColadaLoader,
NavigationResult,
} from 'unplugin-vue-router/runtime'
export function createRouter(options) {
Expand Down
7 changes: 0 additions & 7 deletions src/core/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
} from './RoutesFolderWatcher'
import { generateDTS as _generateDTS } from '../codegen/generateDTS'
import { generateVueRouterProxy as _generateVueRouterProxy } from '../codegen/vueRouterModule'
import { hasNamedExports } from '../data-fetching/parse'
import { definePageTransform, extractDefinePageNameAndPath } from './definePage'
import { EditableTreeNode } from './extendRoutes'

Expand Down Expand Up @@ -117,8 +116,6 @@ export function createRoutesContext(options: ResolvedOptions) {
...routeBlock,
...definedPageNameAndPath,
})
node.value.includeLoaderGuard =
options.dataFetching && (await hasNamedExports(filePath))
}

async function addPage(
Expand Down Expand Up @@ -182,10 +179,6 @@ export function createRoutesContext(options: ResolvedOptions) {
importsMap
)}`

if (options.dataFetching) {
importsMap.add('unplugin-vue-router/runtime', '_HasDataLoaderMeta')
}

// generate the list of imports
let imports = `${importsMap}`
// add an empty line for readability
Expand Down
6 changes: 1 addition & 5 deletions src/core/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,13 +219,9 @@ export class TreeNode {
* Returns the meta property as an object.
*/
get metaAsObject(): Readonly<RouteMeta> {
const meta = {
return {
...this.value.overrides.meta,
}
if (this.value.includeLoaderGuard) {
meta._loaderGuard = true
}
return meta
}

/**
Expand Down
5 changes: 0 additions & 5 deletions src/core/treeNodeValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@ class _TreeNodeValueBase {
private _overrides = new Map<string, RouteRecordOverride>()
// TODO: cache the overrides generation

/**
* Should we add the loader guard to the route record.
*/
includeLoaderGuard: boolean = false

/**
* View name (Vue Router feature) mapped to their corresponding file. By default, the view name is `default` unless
* specified with a `@` e.g. `[email protected]` will have a view name of `aux`.
Expand Down
170 changes: 0 additions & 170 deletions src/data-fetching/README.md

This file was deleted.

Loading

0 comments on commit f0b7b58

Please sign in to comment.