Closed ItsuoSano closed 2 years ago
I've hit this issue continuously trying to write server code. Seems that as soon as you perform an async/await the NuxtApp can no longer be found.
I also meet this error, in the server middleware the request occurs, everything is OK, and if the page hangs and after a couple of minutes I update page, the error is [nuxt] [request error] nuxt instance unavailable -> [Vue warn]: Unhandled error during execution of setup function
+1
composables should be run syncronously in most places. (We do some special magic within the body of middleware, and <script setup>
that makes it possible to mix them in the body of the function, but we don't transform your own composables.)
composables should be run syncronously in most places. (We do some special magic within the body of middleware, and
<script setup>
that makes it possible to mix them in the body of the function, but we don't transform your own composables.)
I'm getting this error when refreshing a page after waiting for some idle time on a page where using useAppFetch I'm waiting for data in a <script setup
useAppFetch is my compossable where I wrapped useFetch and added options there, also catch errors and validate token
@ilyaDegtyarenko Do you have some example code?
@ilyaDegtyarenko Do you have some example code?
Yes, sure
pages/page.vue
<script
setup
lang="ts"
>
const {data, pending, refresh} = await useNuxtApp().$api.operator.paginate(...)
...
plugins/apiServicePlugin.ts
...
export default defineNuxtPlugin(() => {
return {
provide: {
api: {
operator: OperatorService
}
}
}
})
services/operator.service.ts
import {useAppFetch} from '#imports'
export default {
paginate({...}: OperatorPaginate) {
return useAppFetch(`/url`, {...})
},
...
}
composables/useAppFetch.ts
...
export const useAppFetch = async (request: FetchRequest, options: UseFetchOptions<unknown> = {}) => {
options.baseURL = useRuntimeConfig().apiUrl
!options.headers && (options.headers = {})
options.headers['Accept-Language'] = useLang().language.value
const token = useCookie<string>('token')
if (validate(token.value)) {
setAuthHeader(options, token.value)
} else {
const {data, error} = await useNuxtApp().$api.auth.refreshToken(...)
...
}
options.onResponseError = async ({response}: FetchContext & { response: FetchResponse<ResponseType> }): Promise<void> => {
...
}
return useFetch(request, options) as Promise<_AsyncData<any, any>>
}
You should get the nuxt instance before any async operations. And I would suggest that you not use plugins in this context, but expose a shared utility so you don't need to call useNuxtApp
at all to access it.
You should get the nuxt instance before any async operations. And I would suggest that you not use plugins in this context, but expose a shared utility so you don't need to call
useNuxtApp
at all to access it.
I turned the plugin into an utility file that I import into the page component, but I still get an error when refreshing the page after a while.
~/utils/api.ts
import OperatorService from '~/services/operator.service'
export default {
operator: OperatorService
}
page component
import api from '~/utils/api'
const {data, pending, refresh} = await api.operator.paginate()
Error
[Vue warn]: Unhandled error during execution of setup function
at <Operator onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > key="/p/4/setting/operator" >
[nuxt] [request error] nuxt instance unavailable
When I comment on this line, the page opens
// const {data, pending, refresh} = await api.operator.paginate()
And
Where can I make a handshake request before enabling middlewares? With the placement of the token in cookie for further inquiries.
In the server middleware or plugin, which is better? If I trying to do this in the app.vue then there it is done after processing the middleware and redirects are performed
composables should be run syncronously in most places. (We do some special magic within the body of middleware, and
<script setup>
that makes it possible to mix them in the body of the function, but we don't transform your own composables.)
Sorry, i can´t understand yet.
If I can't do any of this, then what should I use in nuxt instead of composables?
Yes, you can call other composables within composables.
Ideally you should not use async functions inside composables. Rather, you would likely want to return an async function so that it can be called within the setup function (or later).
You can get environment variables within composables. But mostly not after an async call.
I'm having this same problem and on top of @hermesalvesbr, I have to say the composable functionality is extremely frustrating with only a very slim chance of usage.
At this point I don't even know the point behind composables anymore - the documentation says it's to make things easier and avoid boilerplate - but instead we ended up with more complicated and fragile code. On top of this, it seems to me that we are slowly getting composable-only features.
This may sound a bit of a rant (and it is really), I've spent a few days trying to get some functionality to work and instead it's jumping back and forth between component hooks and setup composables.
Anyway, I just want to say that (1) there is real frustration behind these "features" and (2) you can see this from end users. So maybe it's still a good time to go one step back and rethink it a bit.
@uuf6429 Thank you for your thoughts.
Rest assured, making things better and more intuitive is top of my mind.
You may find the following helpful in terms of understanding how Vue composables work, and what their limitations are - particularly note the Usage Restrictions
section: https://vuejs.org/guide/reusability/composables.html#composables.
I agree with @uuf6429 understanding how to use the provided composables is extremely difficult. The limitation on async is understandable but I get why people are confused. Nuxt provides a composable for useFetch
which by its very nature is async and therefore people will naturally try to extend that with their own async functionality. I think throwError
is another gotcha; given that most people will want to throw an error after an HTTP request, throwError
has the same limitations and extremely limited usability for actual applications.
Then there is useState
, which is cumbersome to use if it cannot be used after an async event such as an HTTP request. I had better luck adopting pinia
as a storage mechanism and using $fetch directly as necessary. I then use pinia
for a global store for any errors my application may have as well.
Sorry I do not mean to sound as if I am piling on just wanted to share my learnings from trying to adopt Nuxt. I do understand that these concepts are extremely difficult to document accurately in a way that everyone will understand. Given there are many different concepts that share similar names. Middleware for SSR or middleware for the h3 api server? Does server mean the h3 api server or the server performing the SSR?
I haven't found a solution to this, but I came up with a workaround that might be helpful. I have in my app many endpoints that are available globally, they're the same for everyone, and rarely change, so I wanted them to be called only once in the server, cached, and parsed in the frontend, making 0 unnecessary calls.
I've tried to create a composable for this but eventually encountered the same issue found here, so I came up with the following workaround:
const [config, categoryThree, availableComponents, regions] = await Promise.all([
useFetch('/app-config'),
useFetch("/categories/three"),
useFetch(`/editor/cached/available-components`),
useFetch(`/regions`),
])
useState('available-components', () => availableComponents.data.value)
useState('categories-three', () => categoryThree.data.value)
useState('regions', () => regions.data.value)
I'm fetching them all on app.vue
, and then serializing the results with useState()
, then I can access this data everywhere in the app with export const useCategories = () => useState('categories-three') as Ref<Category[]>
. I guess this is probably how this composable was supposed to be used in the first place.
Environment
Darwin
v16.13.0
3.0.0-rc.3-27538180.cad4edd
npm@8.7.0
vite
-
-
Build Modules:
-
Reproduction
https://stackblitz.com/edit/github-cibhp2-szhe5i?file=composables%2Ffetch-data.ts
Describe the bug
when I use
useState
afterasync useFetch
, error was thrownnuxt instance unavailable
Additional context
No response
Logs