From 11a79359b86f1a3ae677fa058a73d150c6a94962 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Mon, 10 Jun 2024 21:51:40 +0100 Subject: [PATCH] fix(nuxt): remove `boolean` value for `dedupe` in v4 compat (#27511) --- docs/1.getting-started/12.upgrade.md | 40 +++++++++++++++++++ .../nuxt/src/app/composables/asyncData.ts | 5 +-- packages/nuxt/src/app/defaults.ts | 1 + packages/nuxt/src/core/templates.ts | 9 +++-- .../basic/pages/useAsyncData/override.vue | 2 +- 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/docs/1.getting-started/12.upgrade.md b/docs/1.getting-started/12.upgrade.md index a50f1f3721..323abdb1d3 100644 --- a/docs/1.getting-started/12.upgrade.md +++ b/docs/1.getting-started/12.upgrade.md @@ -223,6 +223,46 @@ export default defineNuxtConfig({ Please report an issue if you are doing this, as we do not plan to keep this as configurable. +#### Removal of deprecated `boolean` values for `dedupe` option when calling `refresh` in `useAsyncData` and `useFetch` + +🚦 **Impact Level**: Minimal + +##### What Changed + +Previously it was possible to pass `dedupe: boolean` to `refresh`. These were aliases of `cancel` (`true`) and `defer` (`false`). + +```ts twoslash [app.vue] +const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt 3!' })) + +async function refreshData () { + await refresh({ dedupe: true }) +} +``` + +##### Reasons for Change + +These aliases were removed, for greater clarity. + +The issue came up when adding `dedupe` as an option to `useAsyncData`, and we removed the boolean values as they ended up being _opposites_. + +`refresh({ dedupe: false })` meant 'do not _cancel_ existing requests in favour of this new one'. But passing `dedupe: true` within the options of `useAsyncData` means 'do not make any new requests if there is an existing pending request.' (See [PR](https://github.com/nuxt/nuxt/pull/24564#pullrequestreview-1764584361).) + +##### Migration Steps + +The migration should be straightforward: + +```diff + const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt 3!' })) + + async function refreshData () { +- await refresh({ dedupe: true }) ++ await refresh({ dedupe: 'cancel' }) + +- await refresh({ dedupe: false }) ++ await refresh({ dedupe: 'defer' }) + } +``` + #### Respect defaults when clearing `data` in `useAsyncData` and `useFetch` 🚦 **Impact Level**: Minimal diff --git a/packages/nuxt/src/app/composables/asyncData.ts b/packages/nuxt/src/app/composables/asyncData.ts index aafb729e14..8ca773a338 100644 --- a/packages/nuxt/src/app/composables/asyncData.ts +++ b/packages/nuxt/src/app/composables/asyncData.ts @@ -11,7 +11,7 @@ import { onNuxtReady } from './ready' import { asyncDataDefaults, resetAsyncDataToUndefined } from '#build/nuxt.config.mjs' // TODO: temporary module for backwards compatibility -import type { DefaultAsyncDataErrorValue, DefaultAsyncDataValue } from '#app/defaults' +import type { DedupeOption, DefaultAsyncDataErrorValue, DefaultAsyncDataValue } from '#app/defaults' export type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error' @@ -99,7 +99,6 @@ export interface AsyncDataOptions< export interface AsyncDataExecuteOptions { _initial?: boolean - // TODO: remove boolean option in Nuxt 4 /** * Force a refresh, even if there is already a pending request. Previous requests will * not be cancelled, but their result will not affect the data/pending state - and any @@ -108,7 +107,7 @@ export interface AsyncDataExecuteOptions { * Instead of using `boolean` values, use `cancel` for `true` and `defer` for `false`. * Boolean values will be removed in a future release. */ - dedupe?: boolean | 'cancel' | 'defer' + dedupe?: DedupeOption } export interface _AsyncData { diff --git a/packages/nuxt/src/app/defaults.ts b/packages/nuxt/src/app/defaults.ts index c83129cca6..f0dd26ea72 100644 --- a/packages/nuxt/src/app/defaults.ts +++ b/packages/nuxt/src/app/defaults.ts @@ -3,5 +3,6 @@ export type DefaultAsyncDataErrorValue = null export type DefaultAsyncDataValue = null export type DefaultErrorValue = null +export type DedupeOption = boolean | 'cancel' | 'defer' export {} diff --git a/packages/nuxt/src/core/templates.ts b/packages/nuxt/src/core/templates.ts index 0395ff2cbb..9e120da0ff 100644 --- a/packages/nuxt/src/core/templates.ts +++ b/packages/nuxt/src/core/templates.ts @@ -112,6 +112,8 @@ export const pluginsDeclaration: NuxtTemplate = { const pluginsName = (await annotatePlugins(ctx.nuxt, ctx.app.plugins)).filter(p => p.name).map(p => `'${p.name}'`) + const isV4 = ctx.nuxt.options.future.compatibilityVersion === 4 + return `// Generated by Nuxt' import type { Plugin } from '#app' @@ -131,9 +133,10 @@ declare module '#app' { } declare module '#app/defaults' { - type DefaultAsyncDataErrorValue = ${ctx.nuxt.options.future.compatibilityVersion === 4 ? 'undefined' : 'null'} - type DefaultAsyncDataValue = ${ctx.nuxt.options.future.compatibilityVersion === 4 ? 'undefined' : 'null'} - type DefaultErrorValue = ${ctx.nuxt.options.future.compatibilityVersion === 4 ? 'undefined' : 'null'} + type DefaultAsyncDataErrorValue = ${isV4 ? 'undefined' : 'null'} + type DefaultAsyncDataValue = ${isV4 ? 'undefined' : 'null'} + type DefaultErrorValue = ${isV4 ? 'undefined' : 'null'} + type DedupeOption = ${isV4 ? '\'cancel\' | \'defer\'' : 'boolean | \'cancel\' | \'defer\''} } declare module 'vue' { diff --git a/test/fixtures/basic/pages/useAsyncData/override.vue b/test/fixtures/basic/pages/useAsyncData/override.vue index 4741c30054..e0f659a1bc 100644 --- a/test/fixtures/basic/pages/useAsyncData/override.vue +++ b/test/fixtures/basic/pages/useAsyncData/override.vue @@ -15,7 +15,7 @@ if (count || data.value !== 1) { } timeout = 100 -const p = refresh({ dedupe: true, _initial: false }) +const p = refresh({ dedupe: 'cancel', _initial: false }) if (import.meta.client && (count !== 0 || data.value !== 1)) { throw new Error('count should start at 0')