-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
fix(nuxt): reinitialise stale async data #31940
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
WalkthroughThe changes update the internal logic of the In 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🧰 Additional context used🧬 Code Graph Analysis (1)test/nuxt/composables.test.ts (1)
⏰ Context from checks skipped due to timeout of 90000ms (3)
🔇 Additional comments (1)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
packages/nuxt/src/app/composables/fetch.ts (1)
136-137
: Watch list is now simpler but may fire more frequentlyReplacing the previous conditional logic with
watch: watch === false ? [] : [...(watch || []), _fetchOptions]
means every reactive change on_fetchOptions
(including method / baseURL / params / body) will trigger a re-fetch whenwatch !== false
.This is consistent with the refactor in
useAsyncData
, but two caveats are worth keeping in mind:
- Headers or body objects that are recreated on every render (e.g.
{ Authorization: 'Bearer ' + token.value }
) will now invalidate the fetch on every tick even if the effective payload is unchanged.- Large objects placed in
body
will be diffed by Vue’s reactivity tracker; whilst usually fine, this could become a perf hotspot if very large or deeply-nested objects are mutated frequently.If the intent is to re-fetch only on semantic changes, consider hashing the relevant option subset or encouraging users to memoise their option objects.
No action required, just flagging the behaviour change.
packages/nuxt/src/app/composables/asyncData.ts (2)
341-343
: Preventing execution after cache purge avoids stale-fetch misuseRe-assigning
data.execute
to a resolved promise after the cache is purged guarantees that callers cannot accidentally trigger fetches on a cleared instance.
One tiny nit: the new stub still allowsawait data.execute()
but silently does nothing; you may wish to emit a dev-mode warning to aid debugging:-data.execute = () => Promise.resolve() +data.execute = () => { + if (import.meta.dev) { console.warn('[nuxt] execute() called on unregistered asyncData for key "' + key + '"') } + return Promise.resolve() +}Purely optional.
348-364
: Unified watcher is clearer but missesdeep
customisationThe new consolidated watcher
watch([key, ...options.watch || []], ([newKey], [oldKey]) => { ... })makes the flow much easier to follow—good refactor.
Two observations:
options.deep
is not forwarded to this watcher, so nested mutations inside complex watch sources will not be detected unless those sources are themselves reactive proxies. If users pass a plainref(() => ({ foo: { bar: 1 } }))
, deep changes tobar
will be ignored, diverging from howoptions.deep
is applied to the data ref. Consider:-const unsub = watch([key, ...opts], handler) +const unsub = watch([key, ...opts], handler, { deep: options.deep })
- When
oldKey === newKey
,_execute
is called without awaiting. Given debounce(…, 0) this is probably fine, but if a consumer relies on the returned promise it may be worth returning it:-if (oldKey === newKey) { - asyncData._execute({ cause: 'watch', dedupe: options.dedupe }) - return -} +if (oldKey === newKey) { + return asyncData._execute({ cause: 'watch', dedupe: options.dedupe }) +}Neither is critical, yet both would tighten consistency and ergonomics.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/nuxt/src/app/composables/asyncData.ts
(2 hunks)packages/nuxt/src/app/composables/fetch.ts
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: build
- GitHub Check: codeql (javascript-typescript)
- GitHub Check: code
🔇 Additional comments (1)
packages/nuxt/src/app/composables/asyncData.ts (1)
273-277
: Guard now checks for an initialised_deps
flag – good safety netThe switch from a nullish-coalescing assignment to the explicit
if (!nuxtApp._asyncData[key.value]?._deps) { ... }ensures we don’t reuse a partially-initialised async-data record that missed the
_deps
marker. Nice improvement and it fixes the stale-fetcher leak described in #31937.
@nuxt/kit
nuxt
@nuxt/schema
@nuxt/rspack-builder
@nuxt/vite-builder
@nuxt/webpack-builder
commit: |
@danielroe Does it fix that issue too #31939 ? |
possibly i was going to check in a moment but if you have a chance to try the pkg-pr-new... |
CodSpeed Performance ReportMerging #31940 will not alter performanceComparing Summary
|
🔗 Linked issue
reverts #31903
resolves #31937
📚 Description
the
execute
function from previously initialised async data was sticking around, leading to a memory leak and a 'stale' fetcher function which was accessing no-longer-reactive params/refs.