Skip to content

fix(nuxt): use single synced asyncdata instance per key #31373

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

Merged
merged 33 commits into from
Apr 14, 2025

Conversation

danielroe
Copy link
Member

@danielroe danielroe commented Mar 14, 2025

🔗 Linked issue

resolves #21532
resolves #24332 and therefore closes #25850
resolves #22348
resolves #27552
resolves #23522 and therefore closes #23993
resolves #27204
resolves #26733

partly implements #15438

📚 Description

This PR is a major reorganisation of the data fetching layer in Nuxt, providing performance/memory improvements + increased consistency.

⚠️ Breaking Changes (only if v4 compatibility is enabled)

1. getCachedData behavior change

The getCachedData option now:

  • Always gets called before refetching data, even when called by watch or refreshNuxtData
  • It receives a context object with additional information in a cause property
  • Can make more granular decisions about serving cached data
// Before:
useAsyncData('users', fetchUsers, {
  getCachedData: (key, nuxtApp) => {
    return nuxtApp.isHydrating 
      ? nuxtApp.payload.data[key] 
      : nuxtApp.static.data[key]
  }
})

// Now:
useAsyncData('users', fetchUsers, {
  getCachedData: (key, nuxtApp, ctx) => {
    // ctx.cause can be 'initial' | 'refresh:hook' | 'refresh:manual' | 'watch'
    
    // Example: Don't use cache on manual refresh
    if (ctx.cause === 'refresh:manual') return undefined
    
    return cachedData[key]
  }
})

🐞 Bug Fixes

1. Shared refs for the same key

All calls to useAsyncData or useFetch with the same key will now share not just the underlying data but also data, error, and status refs. This ensures consistency across components but may affect code that expected isolated instances.

// Before: These would be independent instances with separate refs
const { data: users1, status: status1 } = useAsyncData('users', () => $fetch('/api/users'))
const { data: users2, status: status2 } = useAsyncData('users', () => $fetch('/api/users'))

// Now: Both reference the same underlying state
// Any changes to one will affect the other

2. Warnings for inconsistent options

Multiple calls to useAsyncData with the same key but different options will now trigger development warnings. The following options must be consistent across all calls with the same key:

  • handler function
  • deep option
  • transform function
  • pick array
  • getCachedData function
  • default value

The following options can differ without triggering warnings:

  • server
  • lazy
  • immediate
  • dedupe
  • watch
// ❌ This will trigger a warning
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false })
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true })

// ✅ This is allowed
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: true })
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: false })

✨ New Features

1. Reactive keys

You can now use computed refs, plain refs or getter functions as keys, allowing for dynamic data fetching that automatically updates when dependencies change:

// Using a computed property as a key
const userId = ref('123')
const { data: user } = useAsyncData(
  computed(() => `user-${userId.value}`),
  () => fetchUser(userId.value)
)

// When userId changes, the data will be automatically refetched
// and the old data will be cleaned up if no other components use it
userId.value = '456'

2. Deduped watch calls

Multiple components watching the same data source (like route changes) will now trigger only a single data refetch:

// In ComponentA.vue
const { data: users } = useAsyncData(
  'users', 
  () => $fetch(`/api/users?page=${route.query.page}`),
  watch: [() => route.query.page]
)

// In ComponentB.vue
const { data: users } = useAsyncData(
  'users', 
  () => $fetch(`/api/users?page=${route.query.page}`),
  watch: [() => route.query.page]
)

// When route.query.page changes, only one fetch will be performed

🔄 Migration Guide

For getCachedData users

If you were using getCachedData, update your implementation to handle the new context parameter:

// Update your getCachedData implementation
useAsyncData('key', fetchFunction, {
  getCachedData: (key, ctx) => {
    // Handle the context object
    if (ctx.cause === 'refresh:manual') {
      // Skip cache on manual refresh
      return
    }
    
    return yourCacheImplementation.get(key)
  }
})

Alternatively, for now, you can disable this behaviour with:

export default defineNuxtConfig({
  experimental: {
    granularCachedData: false,
    purgeCachedData: false
  }
})

For duplicate key users

If you were intentionally using the same key in multiple places:

  1. Use unique keys if you need independent behavior
  2. Or, ensure consistent options across all calls with the same key (see the list of options that must be consistent above)
  3. Consider extracting your data fetching into a composable to ensure consistency:
// composables/useUserData.ts
export function useUserData(userId) {
  return useAsyncData(
    `user-${userId}`,
    () => fetchUser(userId),
    { 
      deep: true,
      transform: (user) => ({ ...user, lastAccessed: new Date() })
    }
  )
}

// Now use this composable everywhere instead of direct useAsyncData calls

🧪 Testing Recommendations

When updating to this version:

  1. Test components that use the same key in multiple places
  2. Verify that reactive UI updates correctly when using shared keys
  3. Test manual refresh behavior with any custom cache implementations
  4. Check that reactive keys work as expected when their dependencies change
  5. Run your app in development mode to catch any warnings about inconsistent options

🚧 TODO

  • consider caching utils to make it easier for people to migrate from getCachedData

Copy link

stackblitz bot commented Mar 14, 2025

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

Copy link

pkg-pr-new bot commented Mar 14, 2025

Open in StackBlitz

@nuxt/kit

npm i https://pkg.pr.new/@nuxt/kit@31373

nuxt

npm i https://pkg.pr.new/nuxt@31373

@nuxt/rspack-builder

npm i https://pkg.pr.new/@nuxt/rspack-builder@31373

@nuxt/schema

npm i https://pkg.pr.new/@nuxt/schema@31373

@nuxt/vite-builder

npm i https://pkg.pr.new/@nuxt/vite-builder@31373

@nuxt/webpack-builder

npm i https://pkg.pr.new/@nuxt/webpack-builder@31373

commit: bfa5a95

Copy link

codspeed-hq bot commented Mar 14, 2025

CodSpeed Performance Report

Merging #31373 will not alter performance

Comparing feat/synced-asyncdata (bfa5a95) with main (31b46e3)

Summary

✅ 10 untouched benchmarks

Copy link
Member

@DamianGlowala DamianGlowala left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Co-authored-by: Damian Głowala <damian.glowala.rebkow@gmail.com>
@Mini-ghost
Copy link
Member

Mini-ghost commented Mar 17, 2025

After this PR, would dedupe no longer be necessary?

From my testing, when the key is the same, setting dedupe to either cancel or defer does not seem to affect the final displayed result. However, when set to cancel, the API gets triggered twice in succession.

Here is the test code I used:

<script lang="ts">
const fetch = () => {
  return new Promise((resolve) => {
    console.log('fetch...')
    setTimeout(() => {
      resolve('Nuxt Data 1')
    }, 1000)
  })
}

function useMyAsyncData() {
  return useAsyncData('NUXT_DATA', fetch, { 
    dedupe: 'cancel' // or 'defer' 
  })
}
</script>

<script setup lang="ts">
const { data: d1 } = useMyAsyncData()
const { data: d2 } = useMyAsyncData()
</script>

Would it make sense to default dedupe to defer, or perhaps even remove this setting in v4 to prevent potential confusion for users regarding repeated API requests?

@danielroe danielroe marked this pull request as ready for review March 17, 2025 13:31
Copy link

coderabbitai bot commented Mar 17, 2025

Walkthrough

The changes introduce a new experimental configuration option, granularCachedData, which controls whether cached responses from asynchronous data fetching are utilised during refreshes. The function signatures for both useAsyncData and useFetch have been updated to include an additional context parameter, providing detailed information on the cause of data requests. New types such as AsyncDataRequestContext and AsyncDataRefreshCause have been added to support this enhanced functionality. Furthermore, the composables now support reactive keys by allowing computed or plain refs as keys, which facilitates dynamic data fetching and the sharing of state across components. The Nuxt configuration has been extended with a new Vite plugin for enhanced development logging. Documentation and upgrade guides have been updated to clarify these modifications, while tests and fixtures have been revised to reflect the new behaviours, including removing outdated test cases.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65f7225 and bfa5a95.

📒 Files selected for processing (1)
  • packages/nuxt/src/app/composables/fetch.ts (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: code
🔇 Additional comments (5)
packages/nuxt/src/app/composables/fetch.ts (5)

3-3: Import type enhancements for reactive support

The addition of MaybeRefOrGetter from Vue signals improved support for reactive values in the composable API.


38-38: Enhanced flexibility with reactive keys

The type change from string to MaybeRefOrGetter<string> enables dynamic data fetching by allowing computed properties or refs as keys, which aligns with the PR objective of supporting reactive keys.


100-102: Improved key generation with reactive support

The key generation logic has been correctly updated to:

  1. Use computed() to create a reactive key
  2. Handle reactive option keys with toValue()
  3. Properly check the value within the computed property

This change supports the PR goal of ensuring consistency when using the same key across components.


108-108: Reactive key computation

Making the final key computation reactive ensures that when a reactive key changes, cached data is properly invalidated and refetched. This is essential for the dynamic data fetching feature mentioned in the PR objectives.


270-272:

❓ Verification inconclusive

Request body included in cache key

Including the request body hash in the cache key ensures requests with identical URLs but different payloads don't share the same cache entry. This is a necessary enhancement to prevent incorrect data being returned from cache.

However, there's a potential performance consideration when hashing large request bodies. For extremely large payloads, this could impact performance.


🏁 Script executed:

#!/bin/bash
# Check if there are any large request bodies being used in the codebase
rg -A 3 -B 3 "useFetch|fetch\(" --type vue --type js --type ts | grep -i -E "body:|body ="

Length of output: 120


Cache Key Improvement Confirmed – Manual Performance Check Advised

The implementation correctly incorporates a hash of the request body into the cache key to prevent mixing responses from requests with identical URLs but different payloads. Our initial automated search did not flag any usage of large request bodies in JavaScript or TypeScript files. However, due to an issue with recognising Vue file types during the search, please verify manually that no Vue components send exceptionally large payloads which could impact performance during hashing.

  • The changes in packages/nuxt/src/app/composables/fetch.ts (lines 270–272) are approved in principle.
  • A manual review of Vue files is recommended to ensure that hashing large bodies (if any) won’t degrade performance.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@danielroe
Copy link
Member Author

Copy link

@coderabbitai coderabbitai bot left a 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 (1)
docs/3.api/2.composables/use-fetch.md (1)

69-82: Subject: Clear Explanation of Reactive Keys and Shared State
The new "Reactive Keys and Shared State" section is a well-crafted addition. It clearly demonstrates how to use a computed or plain ref as the URL to enable dynamic data fetching that automatically updates when the key changes. This example should help users quickly grasp this new feature.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between efa0a80 and a134e34.

📒 Files selected for processing (7)
  • docs/1.getting-started/10.data-fetching.md (3 hunks)
  • docs/1.getting-started/18.upgrade.md (1 hunks)
  • docs/2.guide/3.going-further/1.experimental-features.md (1 hunks)
  • docs/3.api/2.composables/use-async-data.md (5 hunks)
  • docs/3.api/2.composables/use-fetch.md (4 hunks)
  • test/basic.test.ts (0 hunks)
  • test/nuxt/composables.test.ts (7 hunks)
💤 Files with no reviewable changes (1)
  • test/basic.test.ts
🧰 Additional context used
🧬 Code Definitions (1)
test/nuxt/composables.test.ts (3)
packages/nuxt/src/app/composables/asyncData.ts (4)
  • useAsyncData (197-389)
  • useNuxtData (467-489)
  • clearNuxtData (504-516)
  • refreshNuxtData (492-501)
packages/nuxt/src/app/composables/index.ts (5)
  • useAsyncData (2-2)
  • useNuxtData (2-2)
  • clearNuxtData (2-2)
  • refreshNuxtData (2-2)
  • useRoute (15-15)
packages/nuxt/src/app/index.ts (6)
  • useAsyncData (4-4)
  • useNuxtApp (1-1)
  • useNuxtData (4-4)
  • clearNuxtData (4-4)
  • refreshNuxtData (4-4)
  • useRoute (4-4)
🪛 LanguageTool
docs/2.guide/3.going-further/1.experimental-features.md

[uncategorized] ~624-~624: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~626-~626: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::

(UNLIKELY_OPENING_PUNCTUATION)

docs/1.getting-started/10.data-fetching.md

[uncategorized] ~354-~354: Loose punctuation mark.
Context: ...eAsyncData` will be generated for you. ::tip To get the cached data by key, you ...

(UNLIKELY_OPENING_PUNCTUATION)

docs/3.api/2.composables/use-fetch.md

[uncategorized] ~84-~84: Loose punctuation mark.
Context: ...ensures consistency across components. ::warning useFetch is a reserved functi...

(UNLIKELY_OPENING_PUNCTUATION)

docs/1.getting-started/18.upgrade.md

[uncategorized] ~237-~237: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...

(COMMA_COMPOUND_SENTENCE_2)

docs/3.api/2.composables/use-async-data.md

[uncategorized] ~72-~72: Loose punctuation mark.
Context: ...rById(route.params.id) ) </script> ``` ::warning [useAsyncData](/docs/api/comp...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~74-~74: Loose punctuation mark.
Context: ...(/docs/api/composables/use-async-data). :: :read-more{to="/docs/getting-started/...

(UNLIKELY_OPENING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (15)
  • GitHub Check: test-fixtures (windows-latest, built, vite, default, manifest-off, json, 18)
  • GitHub Check: test-fixtures (windows-latest, built, rspack, async, manifest-on, json, 18)
  • GitHub Check: test-fixtures (ubuntu-latest, built, webpack, async, manifest-on, json, 18)
  • GitHub Check: test-fixtures (ubuntu-latest, built, rspack, async, manifest-on, json, 18)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, default, manifest-on, json, 18)
  • GitHub Check: test-fixtures (windows-latest, dev, vite, async, manifest-off, json, 18)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-on, json, 18)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-on, js, 18)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, async, manifest-on, json, 18)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, async, manifest-on, js, 18)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, default, manifest-off, json, 18)
  • GitHub Check: release-pr
  • GitHub Check: test-benchmark
  • GitHub Check: typecheck (windows-latest, bundler)
  • GitHub Check: typecheck (ubuntu-latest, bundler)
🔇 Additional comments (32)
docs/2.guide/3.going-further/1.experimental-features.md (1)

613-627: Well-documented new experimental feature.

The addition of the granularCachedData configuration option enhances the control over caching behavior in Nuxt's data fetching system. This feature allows developers to specify whether the getCachedData function should be called and its result utilised during data refresh operations (via watch, manual refresh or hook-based refresh).

The documentation clearly explains the purpose of this feature with appropriate configuration examples. This aligns with the PR objectives of improving the data fetching layer's performance and consistency.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~624-~624: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~626-~626: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::

(UNLIKELY_OPENING_PUNCTUATION)

docs/1.getting-started/10.data-fetching.md (3)

59-59: Improved apostrophe consistency in documentation.

Fixed the formatting of the possessive form of "Vue" from "Vue's" to "Vue's".


359-397: Excellent documentation for shared state behaviour.

This new section clearly explains an important change in how useAsyncData and useFetch share state when using the same key. The documentation properly categorises which options must remain consistent (handler, deep, transform, pick, getCachedData, default) and which can safely differ (server, lazy, immediate, dedupe, watch).

The examples effectively demonstrate both valid and invalid usages, helping developers avoid potential issues when sharing data between components. This is a crucial addition that aligns with the PR's objective of ensuring consistency across components using the same data references.


398-413: Clear documentation for reactive keys feature.

The new "Reactive Keys" section effectively explains how developers can now use computed refs or plain refs as keys for dynamic data fetching. The example provided clearly demonstrates how changing a reactive key automatically triggers refetching and proper cleanup of old data.

This feature addresses the dynamic data fetching enhancement mentioned in the PR objectives and provides a more elegant approach to managing related data dependencies.

test/nuxt/composables.test.ts (16)

3-10: Enhanced import structure for tests.

Added beforeEach for test setup and included flushPromises from Vue test utils to properly handle async operations in the tests. This improves the test structure and enables better handling of component lifecycle events in the new tests.


134-153: Improved test suite setup with reusable helper function.

The addition of a uniqueKey variable generated for each test ensures test isolation and prevents test cases from interfering with each other. This is particularly important for testing the new shared state behavior.

The mountWithAsyncData helper function is a great abstraction that simplifies testing components that use useAsyncData. It properly wraps the component mounting process and returns both the component instance and the result of useAsyncData, making the tests more readable and maintainable.


157-167: Updated expected keys in return value.

Added clear and status to the expected keys returned by useAsyncData, reflecting the enhanced API that now provides more control over the data lifecycle.


187-199: Updated test to verify shared state behavior.

The test now correctly uses the uniqueKey to ensure test isolation, and adds verification that calling useAsyncData with the same key shares state between instances. This tests the "shared state" feature mentioned in the PR objectives.


211-216: Improved test isolation with uniqueKey.

Updated the test to use the uniqueKey variable instead of hardcoded strings, ensuring that tests don't interfere with each other and properly testing the integration with useNuxtData.


220-230: Enhanced test for useAsyncData after useNuxtData call.

The test now uses uniqueKey for better isolation and explicitly tests the server-side-only data fetching scenario. This verifies that the data fetching and caching behavior works correctly when useNuxtData is called before useAsyncData.


234-239: Better test isolation for refreshNuxtData test.

Updated the test to use uniqueKey for isolation and explicitly cleared data to ensure the refresh behavior is tested from a clean state.


242-281: Comprehensive test for overriding requests.

This new test verifies that requests can be overridden correctly with the new data fetching system. It thoroughly tests various scenarios:

  1. Initial hydration state correctly uses payload data
  2. Requesting data with dedupe: 'cancel' starts but doesn't immediately execute the handler
  3. A second refresh completes and updates the value
  4. The original refresh eventually completes but doesn't affect the value

This test is crucial for ensuring that request deduplication works correctly with the new shared state behavior.


295-339: Thorough test for status tracking across component lifecycles.

This new test verifies that the status of data fetching operations is properly tracked through component mounting, data fetching, and unmounting. It confirms that:

  1. Status starts as "pending" during fetch
  2. Transitions to "success" after data is loaded
  3. Reverts to "idle" when component is unmounted
  4. Correctly handles remounting and refetching

This test is essential for ensuring that components sharing the same data have consistent loading states, as mentioned in the PR objectives.


341-352: Test for caching behavior during refreshes.

This test verifies that the getCachedData function receives the correct context information (specifically the refresh cause) during refreshes triggered by the refresh hook. This is an important part of the new granular caching behavior.


374-403: Comprehensive tests for granular caching behavior.

These three tests thoroughly verify the new caching behavior:

  1. Using cached data on refresh by default
  2. Receiving the correct context (cause: 'initial') on initial fetch
  3. Receiving the correct context (cause: 'refresh:manual') on manual refresh
  4. Receiving the correct context (cause: 'watch') when a watched dependency changes

These tests are crucial for validating the new granularCachedData feature described in the PR objectives.


432-446: Improved test for dedupe with different keys.

Updated the test keys to avoid conflicts with other tests, ensuring proper isolation and more accurate validation of the deduplication feature.


448-482: Comprehensive tests for option consistency warnings.

These new tests verify that appropriate warnings are displayed when incompatible options are used with the same key, including:

  • Mismatching deep option
  • Different transform function
  • Different pick array
  • Different getCachedData function
  • Different handler function

This ensures that developers receive clear guidance when they might unintentionally create inconsistent data references across components, which directly addresses the PR objectives regarding consistency.


484-503: Test for watch call deduplication.

This test verifies that when multiple components watch the same data source, watch calls are deduplicated to reduce unnecessary API requests. This directly validates one of the key PR objectives about deduplication of watch calls.


505-527: Thorough test for reactive keys.

This test properly verifies the new reactive keys feature by:

  1. Using a reactive ref as a key
  2. Confirming the initial data fetch works correctly
  3. Changing the key and verifying the data is automatically refetched
  4. Checking that old data is properly cleaned up when no longer used
  5. Confirming that new data is correctly stored

This validates a key feature mentioned in the PR objectives about using reactive keys for dynamic data fetching.


529-552: Test for proper memory cleanup.

This test verifies that when the last component using data fetched with useAsyncData is unmounted, the data is properly removed from memory. This is important for preventing memory leaks in applications with many components using the same data.

The test correctly:

  1. Mounts multiple components using the same key
  2. Unmounts them one by one
  3. Verifies the data remains available until the last component is unmounted
  4. Confirms the data is completely removed when all components are unmounted

This directly addresses the PR objective regarding memory usage improvements.

docs/1.getting-started/18.upgrade.md (4)

227-236: Clear migration documentation for data fetching changes.

This section effectively introduces the "Singleton Data Fetching Layer" changes, clearly indicating the moderate impact level and explaining the major changes made to Nuxt's data fetching system. The introduction sets proper expectations for users upgrading to the new version.


237-246: Comprehensive explanation of the data fetching changes.

This section clearly explains the four main changes to the data fetching system:

  1. Shared refs for the same key
  2. Enhanced control over getCachedData
  3. Reactive key support
  4. Data cleanup

The explanation about the getCachedData function now receiving a context object is particularly important for users to understand how to migrate their code.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~237-~237: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...

(COMMA_COMPOUND_SENTENCE_2)


247-248: Clear explanation of motivation for changes.

Briefly explains the reasoning behind the changes: improving memory usage and increasing consistency with loading states across calls. This helps users understand why these changes are beneficial.


249-299: Well-structured migration guidance.

This section provides clear, step-by-step migration instructions with:

  1. Guidance on checking for inconsistent options with example code
  2. Suggestion to extract shared calls into composables for better consistency
  3. Examples showing how to update getCachedData implementations for the new context parameter
  4. Configuration options to disable the new behavior if needed

The examples are particularly helpful in illustrating both the issues to look for and how to resolve them, making it easier for developers to migrate their applications.

docs/3.api/2.composables/use-fetch.md (2)

130-133: Subject: Updated getDefaultCachedData Snippet
The revised getDefaultCachedData now accepts the additional ctx parameter. This enhancement provides more granular control over caching behaviour during hydration versus static rendering. Please ensure that the accompanying documentation and any related examples are updated to reflect this change.


202-205: Subject: New AsyncDataRequestContext Type Declaration
Introducing the AsyncDataRequestContext type with its cause property significantly improves the clarity and safety of the caching strategy by explaining why a data request is being made. This addition helps maintain consistency between useFetch and useAsyncData.

docs/3.api/2.composables/use-async-data.md (6)

56-71: Subject: Clear Reactive Keys Example
The "Reactive Keys" section now shows an excellent example of using a computed ref as the key for useAsyncData. This dynamic approach to key management is clear and concise, which should aid users in implementing reactive data fetching effectively.


93-97: Subject: Updated getDefaultCachedData Snippet
The snippet for getDefaultCachedData has been updated to include the ctx parameter. This change enhances cache retrieval decisions by considering the context of the data request (e.g. hydration state). It would be good to ensure consistency in documentation across both composables.


118-136: Subject: Detailed Shared State and Option Consistency Section
This new section comprehensively details which options must remain consistent when sharing state across multiple useAsyncData calls. The inclusion of examples demonstrating both compliant and non-compliant scenarios reinforces best practices. Note that this guidance mirrors earlier reviews, so please verify that the updated documentation does not conflict with previous guidance.


170-178: Subject: Updated Function Signature for Reactive Keys
Expanding the key parameter to accept Ref<string> and ComputedRef<string> greatly increases flexibility for dynamic data fetching. This update is forward-thinking and aligns well with modern Vue practices.


189-191: Subject: Enhanced getCachedData Option in AsyncDataOptions
Including the ctx parameter in the getCachedData function signature standardises caching behaviour between useAsyncData and useFetch. This update should help developers implement more robust caching logic based on the request’s context.


193-196: Subject: New AsyncDataRequestContext Type
The addition of the AsyncDataRequestContext type, featuring the cause property, provides critical context for data requests. This improvement supports clearer debugging and more predictable cache handling.

@ljcremer
Copy link

ljcremer commented Apr 7, 2025

Will this fix the issue where useFetch does not work with a reactive key as in the issue
#21532

Copy link

@coderabbitai coderabbitai bot left a 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 (2)
docs/1.getting-started/18.upgrade.md (1)

273-288: Consider adding code comments for clarity in the diff example

While the diff example for updating getCachedData is good, it would be helpful to add more inline comments explaining what each case of ctx.cause represents and when it might be useful to handle differently.

useAsyncData('key', fetchFunction, {
-  getCachedData: (key, nuxtApp) => {
-    return cachedData[key]
-  }
+  getCachedData: (key, nuxtApp, ctx) => {
+    // ctx.cause - can be 'initial' | 'refresh:hook' | 'refresh:manual' | 'watch'
+    
+    // Example: Don't use cache on manual refresh
+    if (ctx.cause === 'refresh:manual') return undefined
+    
+    // Example: Use different caching strategy for watch-triggered refreshes
+    if (ctx.cause === 'watch') {
+      // Custom watch caching logic
+    }
+    
+    return cachedData[key]
+  }
})
docs/3.api/2.composables/use-fetch.md (1)

83-83: Spacing issue after the sentence

There's an extra space before the ::warning directive which could affect rendering.

-When using `useFetch` with the same URL and options in multiple components, they will share the same `data`, `error` and `status` refs. This ensures consistency across components. 
+When using `useFetch` with the same URL and options in multiple components, they will share the same `data`, `error` and `status` refs. This ensures consistency across components.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a134e34 and b05d5f9.

📒 Files selected for processing (10)
  • docs/1.getting-started/10.data-fetching.md (3 hunks)
  • docs/1.getting-started/18.upgrade.md (1 hunks)
  • docs/2.guide/3.going-further/1.experimental-features.md (1 hunks)
  • docs/3.api/2.composables/use-async-data.md (5 hunks)
  • docs/3.api/2.composables/use-fetch.md (4 hunks)
  • packages/nuxt/src/app/composables/asyncData.ts (17 hunks)
  • packages/nuxt/src/app/composables/fetch.ts (1 hunks)
  • packages/schema/src/config/experimental.ts (1 hunks)
  • test/fixtures/basic-types/types.ts (1 hunks)
  • test/nuxt/composables.test.ts (8 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/schema/src/config/experimental.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
test/nuxt/composables.test.ts (4)
packages/nuxt/src/app/composables/asyncData.ts (4)
  • useAsyncData (197-389)
  • useNuxtData (493-515)
  • clearNuxtData (530-542)
  • refreshNuxtData (518-527)
packages/nuxt/src/app/composables/index.ts (5)
  • useAsyncData (2-2)
  • useNuxtData (2-2)
  • clearNuxtData (2-2)
  • refreshNuxtData (2-2)
  • useRoute (15-15)
packages/nuxt/src/app/nuxt.ts (1)
  • useNuxtApp (539-552)
packages/nuxt/src/app/composables/router.ts (1)
  • useRoute (20-28)
test/fixtures/basic-types/types.ts (1)
packages/nuxt/src/app/composables/asyncData.ts (2)
  • useAsyncData (197-389)
  • useLazyAsyncData (472-490)
🪛 LanguageTool
docs/1.getting-started/18.upgrade.md

[uncategorized] ~237-~237: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...

(COMMA_COMPOUND_SENTENCE_2)

docs/1.getting-started/10.data-fetching.md

[uncategorized] ~354-~354: Loose punctuation mark.
Context: ...eAsyncData` will be generated for you. ::tip To get the cached data by key, you ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~358-~358: Loose punctuation mark.
Context: ...docs/api/composables/use-nuxt-data) :: :video-accordion{title="Watch a video fro...

(UNLIKELY_OPENING_PUNCTUATION)

docs/2.guide/3.going-further/1.experimental-features.md

[uncategorized] ~620-~620: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~622-~622: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::

(UNLIKELY_OPENING_PUNCTUATION)

docs/3.api/2.composables/use-async-data.md

[uncategorized] ~72-~72: Loose punctuation mark.
Context: ...rById(route.params.id) ) </script> ``` ::warning [useAsyncData](/docs/api/comp...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~74-~74: Loose punctuation mark.
Context: ...(/docs/api/composables/use-async-data). :: :read-more{to="/docs/getting-started/...

(UNLIKELY_OPENING_PUNCTUATION)

docs/3.api/2.composables/use-fetch.md

[uncategorized] ~84-~84: Loose punctuation mark.
Context: ...ensures consistency across components. ::warning useFetch is a reserved functi...

(UNLIKELY_OPENING_PUNCTUATION)

🔇 Additional comments (45)
docs/2.guide/3.going-further/1.experimental-features.md (1)

609-623: Well-documented new experimental feature.

The addition of the granularCachedData feature is clearly explained with both its purpose and usage example. This feature provides more control over data fetching behavior by allowing the result from getCachedData to be utilized during refresh operations.

The code example is straightforward and follows the established pattern of other experimental features in this document. The inclusion of a link to the GitHub PR for implementation details provides valuable context for developers who want to understand the inner workings.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~620-~620: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~622-~622: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::

(UNLIKELY_OPENING_PUNCTUATION)

packages/nuxt/src/app/composables/fetch.ts (2)

100-103: Enhanced key reactivity for dynamic data fetching.

The key computation has been wrapped in a computed() function, making it reactive to changes in its dependencies. This allows for more dynamic behavior when using reactive URL parameters or other changing values. The error handling has also been updated accordingly to check _key.value.

This change is crucial for the reactive keys feature, allowing the composable to respond to changes in the key's dependencies and automatically refetch data when needed.


108-108: Reactive key computation for consistent behavior.

The key variable is now also made reactive through computed(), ensuring it stays in sync with the _key value. This maintains the special prefixing logic ($f) for automatically generated keys while preserving reactivity.

This change ensures that the internal key tracking remains consistent when using reactive keys.

test/fixtures/basic-types/types.ts (2)

548-552: Good type tests for computed key support in useAsyncData.

These tests verify that useAsyncData correctly handles computed properties as keys. The expectTypeOf assertions ensure that the function's return type is properly inferred even when using a computed key instead of a string literal.

This ensures type safety when developers use the new reactive key functionality.


553-556: Type tests for computed key support in useLazyAsyncData.

Similar to the tests for useAsyncData, these assertions verify that useLazyAsyncData properly handles computed property keys with correct type inference.

These tests are important to ensure consistent behavior between the eager and lazy variants of the composable.

docs/1.getting-started/10.data-fetching.md (3)

59-59: Minor grammatical fix.

Corrected possessive apostrophe in "Vue's".


361-398: Clear documentation on shared state and option consistency.

This new section clearly explains how multiple components using the same key will share state, which is crucial information for developers. The documentation helpfully categorizes which options must be consistent across calls with the same key and which can safely differ.

The examples show both incorrect usage that will trigger warnings and correct patterns, providing practical guidance for developers.


400-415: Excellent documentation on reactive keys feature.

This section explains the new ability to use computed refs, plain refs, or getter functions as keys, enabling dynamic data fetching. The example clearly demonstrates how data can be automatically refetched when dependencies change.

This is a powerful addition that makes data fetching more flexible and reactive, aligning with Vue's reactive programming model.

test/nuxt/composables.test.ts (12)

134-139: Well structured test isolation with uniqueKey

Adding a unique key generator for each test ensures proper isolation between test cases and prevents test interference when using the same keys across tests.


141-153: Great helper function for testing async data

The mountWithAsyncData function is a valuable testing utility that encapsulates the complexity of mounting components with async data handling. It returns both the component instance and async data result, making tests more readable and maintainable.


195-206: Confirms expected shared state behavior

This test correctly verifies that multiple calls to useAsyncData with the same key share the same refs, which is a key feature of the new singleton data fetching layer. It also tests the warning that appears when incompatible options are used.


249-288: Comprehensive test for request overriding

This test thoroughly validates the request prioritization behavior when overriding requests. It ensures that:

  1. Initial data from payload is respected
  2. Cancellation works with the dedupe: 'cancel' option
  3. New requests properly update the shared data

The sequence of test steps effectively demonstrates the intended behavior.


302-346: Validates status lifecycle for async requests

Good test coverage of the status transitions (idle → pending → success) throughout the component lifecycle, including unmounting scenarios. This ensures the status ref is accurately maintained.


348-359: Tests cache refresh behavior with context

This test verifies that getCachedData receives the proper context information during refreshes. It confirms the context contains the correct cause value for refresh operations triggered by hooks.


381-386: Verifies cache usage on refresh

Good test to confirm the default behavior of using cache on refresh, ensuring that fetched data respects the cached value returned by getCachedData.


388-410: Validates context parameter in different scenarios

These tests thoroughly check that the getCachedData function receives the correct cause value in different scenarios:

  • Initial fetch
  • Manual refresh
  • Watch-triggered refresh

This ensures the context parameter works correctly in all relevant cases.


455-490: Comprehensive testing of option consistency warnings

Excellent coverage of the warning system for incompatible options. The test validates warnings for different incompatible options (deep, transform, pick, getCachedData, and handler function differences) ensuring users get proper guidance when mixing configurations with the same key.


493-512: Tests for watch deduplicated refreshes

This test confirms that when a watched dependency changes, useAsyncData only refreshes once, preventing redundant API calls. This is crucial for performance when multiple components watch the same data source.


514-547: Validates reactive key support

This test thoroughly checks the reactive key functionality with both ref and getter approaches. It verifies that:

  1. Data is refetched when the key changes
  2. Previous data is properly cleaned up
  3. The payload correctly reflects the current key's data

Great coverage of this important new feature.


549-572: Validates memory cleanup on component unmount

This test ensures that when the last component using a particular key is unmounted, the associated data is cleaned up. This is important to prevent memory leaks in applications with many components and data fetches.

docs/1.getting-started/18.upgrade.md (2)

227-246: Clearly explains the major data fetching changes

This section provides a high-level overview of the significant changes to Nuxt's data fetching system. The impact level classification as "Moderate" is appropriate given the scope of changes.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~237-~237: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...

(COMMA_COMPOUND_SENTENCE_2)


247-299: Excellent migration guide with clear examples

The migration steps are well-documented with practical examples that illustrate:

  1. How to extract shared data fetching into composables for consistency
  2. How to update getCachedData implementations to handle the new context parameter
  3. Configuration options to disable new behaviors if needed

This provides users with a clear path forward when upgrading.

docs/3.api/2.composables/use-fetch.md (2)

69-84: Well-explained reactive keys and shared state features

The new section clearly explains how to use computed refs or plain refs as dynamic URLs, which is a powerful feature for data fetching that updates automatically with route changes. The shared state explanation is concise and clear.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~84-~84: Loose punctuation mark.
Context: ...ensures consistency across components. ::warning useFetch is a reserved functi...

(UNLIKELY_OPENING_PUNCTUATION)


189-201: Updated signature and added context type

The updated getCachedData signature with the new context parameter aligns with the implementation changes. The AsyncDataRequestContext type is well-documented with clear descriptions of the possible causes.

docs/3.api/2.composables/use-async-data.md (4)

56-72: Clear explanation of reactive keys with example

This section provides a good explanation of how reactive keys work, with a practical example using route parameters. The explanation makes it clear that data will be automatically refetched when the key changes.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~72-~72: Loose punctuation mark.
Context: ...rById(route.params.id) ) </script> ``` ::warning [useAsyncData](/docs/api/comp...

(UNLIKELY_OPENING_PUNCTUATION)


116-144: Comprehensive explanation of shared state rules

This section does an excellent job explaining the shared state behavior and clearly outlines which options must be consistent across calls with the same key and which ones can differ. The examples for both valid and invalid cases provide clear guidance to users.


173-173: Updated function signature to support reactive keys

The function signature now correctly reflects the support for ref and computed ref keys, which is consistent with the new reactive keys feature described in the documentation.


188-194: Updated signature and added context type

The getCachedData function signature has been properly updated with the context parameter, and the AsyncDataRequestContext type is well-documented. This ensures type safety when implementing custom cache strategies based on the fetch cause.

packages/nuxt/src/app/composables/asyncData.ts (17)

44-44: Well-defined type for refresh causes

The new AsyncDataRefreshCause type clearly categorizes the different scenarios that trigger data refreshing, enabling more nuanced caching behavior based on the refresh context.


71-71: Enhanced getCachedData signature with context parameter

The updated signature now includes a context object with the refresh cause, allowing for more intelligent caching decisions based on why the data is being refreshed.


175-175: Support for reactive keys

Converting the key parameter from string to MaybeRefOrGetter<string> enables dynamic data fetching with reactive keys, a significant improvement that allows components to share the same underlying data even when keys are computed.

Also applies to: 193-193, 449-449, 467-467


205-205: Key validation logic for reactive keys

The updated signature handling now correctly supports both string literals and reactive values, with proper type checking that ensures keys are always strings when resolved.

Also applies to: 211-212


224-232: Improved cached data retrieval logic

The default implementation of getCachedData now intelligently handles different refresh causes, only using static data when appropriate (not during manual refreshes or hook-triggered ones).


249-271: Option consistency validation

This new check warns developers when using the same key with inconsistent options or handlers, preventing subtle bugs that could arise from conflicting configurations.


275-276: Shared asyncData instance for same key

Creating a single shared instance for each unique key ensures consistent state across components, addressing the issues mentioned in PR objectives around state synchronization.


278-278: Resource cleanup with dependency tracking

The dependency counter and unregister mechanism ensure proper cleanup of resources when components are unmounted, preventing memory leaks while preserving shared state when needed.

Also applies to: 338-350


332-332: Deduplication of watch execution

Using the shared async data instance for watch callbacks ensures that multiple components watching the same data with the same key won't trigger duplicate API requests, solving one of the key issues mentioned in the PR objectives.


353-364: Key change handling

This watch mechanism elegantly handles reactive key changes by cleaning up old keys and initializing new ones, maintaining proper dependency tracking throughout key changes.


374-382: State synchronization with writableComputedRef

Using computed refs to maintain connections to the shared state ensures that all components using the same key will always see the same data, errors, and status - even if the key changes.


384-386: Promise handling improvements

The promise handling has been improved to ensure that awaiting on asyncData returns the correct references even after key changes, maintaining backward compatibility.


391-400: Utility for writable computed refs

This helper function creates computed refs that maintain a bidirectional connection to the underlying shared state, enabling both reading and writing to the shared data.


577-578: Encapsulated async data creation

The new createAsyncData function cleanly encapsulates all the logic for creating and managing async data instances, separating concerns and making the code more maintainable.

Also applies to: 581-695


619-627: Enhanced caching behavior

The implementation now checks for cached data with appropriate context, supporting the new granularCachedData configuration option mentioned in the summary, which gives more control over when cached responses are used.


683-683: Debounced execution

The debounced execution function prevents excessive calls when multiple components trigger the same data fetch simultaneously, addressing performance concerns mentioned in the PR objectives.


697-704: Hash-based option comparison

The hash function creates consistent identifiers for handlers and options, enabling reliable comparison of configuration to detect inconsistencies when using the same key.

Copy link

@coderabbitai coderabbitai bot left a 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 (2)
docs/2.guide/3.going-further/1.experimental-features.md (1)

609-624: Refine Punctuation and Consistency in "granularCachedData" Section

The new "granularCachedData" section is very informative and clearly explains the feature. However, please review the punctuation around lines 620–622—as static analysis hints suggest there are some loose punctuation marks—to ensure consistent and clear formatting throughout the documentation.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~620-~620: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~622-~622: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::

(UNLIKELY_OPENING_PUNCTUATION)

docs/1.getting-started/18.upgrade.md (1)

249-256: Clarify Inconsistent Options Migration Step

The migration step addressing potential inconsistencies when using the same key with different options is clearly demonstrated by the example. It might be helpful to emphasise to developers why maintaining consistency in options (such as deep, transform, etc.) is critical, to prevent unexpected warnings.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b05d5f9 and 66ccaeb.

📒 Files selected for processing (3)
  • docs/1.getting-started/18.upgrade.md (1 hunks)
  • docs/2.guide/3.going-further/1.experimental-features.md (1 hunks)
  • packages/schema/src/config/experimental.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/schema/src/config/experimental.ts
🧰 Additional context used
🪛 LanguageTool
docs/1.getting-started/18.upgrade.md

[uncategorized] ~238-~238: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...

(COMMA_COMPOUND_SENTENCE_2)

docs/2.guide/3.going-further/1.experimental-features.md

[uncategorized] ~620-~620: Loose punctuation mark.
Context: ... granularCachedData: true } }) ``` ::read-more{icon="i-simple-icons-github" ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~622-~622: Loose punctuation mark.
Context: ...e PR #31373 for implementation details. ::

(UNLIKELY_OPENING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: release-pr
  • GitHub Check: codeql (javascript-typescript)
🔇 Additional comments (9)
docs/1.getting-started/18.upgrade.md (9)

228-242: Singleton Data Fetching Layer: Overview and Impact

The newly introduced "Singleton Data Fetching Layer" section effectively outlines the key changes, including shared refs for identical keys, improved control over the caching function via an updated signature, reactive key support, and automatic data cleanup. This provides users with a solid understanding of the performance and consistency improvements.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~238-~238: Use a comma before “and” if it connects two independent clauses (unless they are closely connected and short).
Context: ...(Previously, new data was always fetched and this function was not called in these c...

(COMMA_COMPOUND_SENTENCE_2)


273-288: Update to getCachedData Signature

The diff showing the update of the getCachedData function signature—adding the new ctx parameter and checking for a manual refresh via ctx.cause—is clear and precise. This change provides a more granular caching strategy, and the inline comment enhances understanding.


290-299: Alternative Configuration for Caching Behaviour

Providing an alternative configuration snippet to disable the new caching behaviour (via granularCachedData and purgeCachedData) is very useful for users who may prefer previous behaviours. The instructions make it clear how to revert the changes if necessary.


320-325: Update Route Metadata Access

The diff example that changes the access from route.meta.name to route.name succinctly addresses the modifications in how route metadata is exposed. This simplification is in line with the updated Nuxt architecture and should reduce ambiguity.


477-487: Simplify Handling of error.data

Replacing manual JSON parsing of error.data with direct assignment clarifies the intent and reduces potential parsing errors. This improvement also aligns with the updated error handling strategy, where the error object now provides pre-parsed data.


669-678: Replace Boolean Values for dedupe Option

The diff replacing boolean values with explicit string values ('cancel' and 'defer') for the dedupe option improves clarity significantly. This change removes the ambiguity associated with using true/false values and makes the API behaviour more predictable.


769-776: Ensure Absolute Watch Paths for Builder Hooks

The added logic using relative and resolve from Node’s fs module ensures that paths emitted in the builder:watch hook are absolute with respect to the project’s source directory. This update enhances compatibility with layered architectures and complex projects.


797-799: Transition from Global window.__NUXT__ Access

Switching from using the global window.__NUXT__ object to accessing Nuxt payload via useNuxtApp().payload is a commendable update. This move promotes better separation of concerns and supports multi-app patterns, aligning with modern Nuxt practices.


860-867: Revise Template Compilation with getContents

The refactoring of template compilation—moving from a static src reference to a dynamic getContents function that utilises a template utility from es-toolkit/compat—is a robust improvement. This approach not only enhances flexibility but also addresses security concerns associated with using lodash’s template function at build time.

@danielroe danielroe merged commit 724e1a6 into main Apr 14, 2025
48 of 49 checks passed
@danielroe danielroe deleted the feat/synced-asyncdata branch April 14, 2025 16:04
This was referenced Apr 14, 2025
@github-actions github-actions bot mentioned this pull request Apr 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment