Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

fix(nuxt): pass async-data errors through to client #8521

Merged
merged 5 commits into from Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/nuxi/package.json
Expand Up @@ -35,7 +35,7 @@
"execa": "^6.1.0",
"flat": "^5.0.2",
"giget": "^0.1.7",
"h3": "^0.8.5",
"h3": "^0.8.6",
"jiti": "^1.16.0",
"listhen": "^0.3.4",
"mlly": "^0.5.16",
Expand Down
2 changes: 1 addition & 1 deletion packages/nuxt/package.json
Expand Up @@ -52,7 +52,7 @@
"escape-string-regexp": "^5.0.0",
"fs-extra": "^10.1.0",
"globby": "^13.1.2",
"h3": "^0.8.5",
"h3": "^0.8.6",
"hash-sum": "^2.0.0",
"hookable": "^5.4.1",
"knitwork": "^0.1.2",
Expand Down
18 changes: 10 additions & 8 deletions packages/nuxt/src/app/composables/asyncData.ts
@@ -1,6 +1,7 @@
import { onBeforeMount, onServerPrefetch, onUnmounted, ref, getCurrentInstance, watch, unref } from 'vue'
import type { Ref, WatchSource } from 'vue'
import { NuxtApp, useNuxtApp } from '../nuxt'
import { createError } from './error'

export type _Transform<Input = any, Output = any> = (input: Input) => Output

Expand Down Expand Up @@ -61,7 +62,7 @@ export function useAsyncData<
> (
handler: (ctx?: NuxtApp) => Promise<DataT>,
options?: AsyncDataOptions<DataT, Transform, PickKeys>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null>
export function useAsyncData<
DataT,
DataE = Error,
Expand All @@ -71,13 +72,13 @@ export function useAsyncData<
key: string,
handler: (ctx?: NuxtApp) => Promise<DataT>,
options?: AsyncDataOptions<DataT, Transform, PickKeys>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null>
export function useAsyncData<
DataT,
DataE = Error,
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
> (...args: any[]): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true> {
> (...args: any[]): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null> {
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
if (typeof args[0] !== 'string') { args.unshift(autoKey) }

Expand Down Expand Up @@ -114,7 +115,7 @@ export function useAsyncData<
nuxt._asyncData[key] = {
data: ref(useInitialCache() ? nuxt.payload.data[key] : options.default?.() ?? null),
pending: ref(!useInitialCache()),
error: ref(nuxt.payload._errors[key] ?? null)
error: ref(nuxt.payload._errors[key] ? createError(nuxt.payload._errors[key]) : null)
}
}
// TODO: Else, Soemhow check for confliciting keys with different defaults or fetcher
Expand Down Expand Up @@ -168,7 +169,8 @@ export function useAsyncData<
asyncData.pending.value = false
nuxt.payload.data[key] = asyncData.data.value
if (asyncData.error.value) {
nuxt.payload._errors[key] = true
// We use `createError` and its .toJSON() property to normalize the error
nuxt.payload._errors[key] = createError(asyncData.error.value)
}
delete nuxt._asyncDataPromises[key]
})
Expand Down Expand Up @@ -240,7 +242,7 @@ export function useLazyAsyncData<
> (
handler: (ctx?: NuxtApp) => Promise<DataT>,
options?: Omit<AsyncDataOptions<DataT, Transform, PickKeys>, 'lazy'>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null>
export function useLazyAsyncData<
DataT,
DataE = Error,
Expand All @@ -250,13 +252,13 @@ export function useLazyAsyncData<
key: string,
handler: (ctx?: NuxtApp) => Promise<DataT>,
options?: Omit<AsyncDataOptions<DataT, Transform, PickKeys>, 'lazy'>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null>
export function useLazyAsyncData<
DataT,
DataE = Error,
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
> (...args: any[]): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true> {
> (...args: any[]): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null> {
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
const [key, handler, options] = args as [string, (ctx?: NuxtApp) => Promise<DataT>, AsyncDataOptions<DataT, Transform, PickKeys>]
Expand Down
4 changes: 2 additions & 2 deletions packages/nuxt/src/app/composables/fetch.ts
Expand Up @@ -30,7 +30,7 @@ export function useFetch<
> (
request: Ref<ReqT> | ReqT | (() => ReqT),
opts?: UseFetchOptions<_ResT, Transform, PickKeys>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, ErrorT | null | true>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, ErrorT | null>
export function useFetch<
ResT = void,
ErrorT = FetchError,
Expand Down Expand Up @@ -114,7 +114,7 @@ export function useLazyFetch<
> (
request: Ref<ReqT> | ReqT | (() => ReqT),
opts?: Omit<UseFetchOptions<_ResT, Transform, PickKeys>, 'lazy'>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, ErrorT | null | true>
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, ErrorT | null>
export function useLazyFetch<
ResT = void,
ErrorT = FetchError,
Expand Down
2 changes: 1 addition & 1 deletion packages/vite/package.json
Expand Up @@ -33,7 +33,7 @@
"externality": "^0.2.2",
"fs-extra": "^10.1.0",
"get-port-please": "^2.6.1",
"h3": "^0.8.5",
"h3": "^0.8.6",
"knitwork": "^0.1.2",
"magic-string": "^0.26.7",
"mlly": "^0.5.16",
Expand Down
20 changes: 10 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions test/fixtures/basic/types.ts
Expand Up @@ -28,17 +28,17 @@ describe('API routes', () => {
expectTypeOf(useAsyncData('api-other', () => $fetch('/api/other')).data).toEqualTypeOf<Ref<unknown>>()
expectTypeOf(useAsyncData<TestResponse>('api-generics', () => $fetch('/test')).data).toEqualTypeOf<Ref<TestResponse>>()

expectTypeOf(useAsyncData('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<Error | true | null>>()
expectTypeOf(useAsyncData<any, string>('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<string | true | null>>()
expectTypeOf(useAsyncData('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<Error | null>>()
expectTypeOf(useAsyncData<any, string>('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<string | null>>()

expectTypeOf(useLazyAsyncData('lazy-api-hello', () => $fetch('/api/hello')).data).toEqualTypeOf<Ref<string>>()
expectTypeOf(useLazyAsyncData('lazy-api-hey', () => $fetch('/api/hey')).data).toEqualTypeOf<Ref<{ foo: string, baz: string }>>()
expectTypeOf(useLazyAsyncData('lazy-api-hey-with-pick', () => $fetch('/api/hey'), { pick: ['baz'] }).data).toEqualTypeOf<Ref<{ baz: string }>>()
expectTypeOf(useLazyAsyncData('lazy-api-other', () => $fetch('/api/other')).data).toEqualTypeOf<Ref<unknown>>()
expectTypeOf(useLazyAsyncData<TestResponse>('lazy-api-generics', () => $fetch('/test')).data).toEqualTypeOf<Ref<TestResponse>>()

expectTypeOf(useLazyAsyncData('lazy-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<Error | true | null>>()
expectTypeOf(useLazyAsyncData<any, string>('lazy-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<string | true | null>>()
expectTypeOf(useLazyAsyncData('lazy-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<Error | null>>()
expectTypeOf(useLazyAsyncData<any, string>('lazy-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<string | null>>()
})

it('works with useFetch', () => {
Expand All @@ -48,8 +48,8 @@ describe('API routes', () => {
expectTypeOf(useFetch('/api/other').data).toEqualTypeOf<Ref<unknown>>()
expectTypeOf(useFetch<TestResponse>('/test').data).toEqualTypeOf<Ref<TestResponse>>()

expectTypeOf(useFetch('/error').error).toEqualTypeOf<Ref<FetchError | null | true>>()
expectTypeOf(useFetch<any, string>('/error').error).toEqualTypeOf<Ref<string | null | true>>()
expectTypeOf(useFetch('/error').error).toEqualTypeOf<Ref<FetchError | null>>()
expectTypeOf(useFetch<any, string>('/error').error).toEqualTypeOf<Ref<string | null>>()

expectTypeOf(useLazyFetch('/api/hello').data).toEqualTypeOf<Ref<string>>()
expectTypeOf(useLazyFetch('/api/hey').data).toEqualTypeOf<Ref<{ foo: string, baz: string }>>()
Expand All @@ -58,8 +58,8 @@ describe('API routes', () => {
expectTypeOf(useLazyFetch('/api/other').data).toEqualTypeOf<Ref<unknown>>()
expectTypeOf(useLazyFetch<TestResponse>('/test').data).toEqualTypeOf<Ref<TestResponse>>()

expectTypeOf(useLazyFetch('/error').error).toEqualTypeOf<Ref<FetchError | null | true>>()
expectTypeOf(useLazyFetch<any, string>('/error').error).toEqualTypeOf<Ref<string | null | true>>()
expectTypeOf(useLazyFetch('/error').error).toEqualTypeOf<Ref<FetchError | null>>()
expectTypeOf(useLazyFetch<any, string>('/error').error).toEqualTypeOf<Ref<string | null>>()
})
})

Expand Down