Skip to content

fix(data-loaders): ignore leaked loader context in components#2727

Draft
posva wants to merge 1 commit into
mainfrom
fix/data-loaders-nested-lazy-context-leak
Draft

fix(data-loaders): ignore leaked loader context in components#2727
posva wants to merge 1 commit into
mainfrom
fix/data-loaders-nested-lazy-context-leak

Conversation

@posva

@posva posva commented Jun 1, 2026

Copy link
Copy Markdown
Member

WIP / draft — opening early for visibility, feedback welcome.

Closes #2684

Problem

When all loaders on a route are lazy, navigation completes while the loaders are still pending. A nested lazy loader (e.g. child that awaits parent and then keeps loading) leaves the module-level loader current context pointing at its own entry. If a component renders during that window, useDataLoader() called in setup() reads that stale context as its parent, which:

  • re-runs the parent loader (the "parent-page" loader is called twice on initial load),
  • makes a loader nest under itself ("…" has itself as parent),
  • and, with two loaders in the same component, spins into an infinite render → reload loop.

The context global is set around a loader's execution and restored on .finally; lazy loaders restore it after navigation, racing with component rendering.

Fix

In useDataLoader, when invoked from inside a component (getCurrentInstance()) and not synchronously within a loader function, drop the ambient context — in a component, loaders are always used at the root. A small depth counter (runInsideLoaderFn / isInsideLoaderFn in utils.ts) wraps the actual loader-function call so genuinely nested loaders still nest correctly, even when first triggered synchronously from a component. Applied to both defineBasicLoader and defineColadaLoader.

Test

Added a regression test to the shared tester.ts (runs for basic + Colada): a parent loader that resolves instantly, a child loader that nests it and keeps loading, and parent/child components that use the loaders directly. Written before the fix and confirmed failing first ("has itself as parent" warning + parent loader called twice); passes after.

Checks

  • pnpm test:unit — full suite passes (1629)
  • pnpm test:types
  • lint + format clean
  • changelog / docs (if needed)

A still-pending lazy nested loader leaves the module-level loader
context set to its own entry. When a component renders during that
window, `useDataLoader()` in `setup()` reads the stale context as its
parent, which re-runs the parent loader, nests a loader under itself
("… has itself as parent") and can spin into an infinite render loop.

In a component, loaders are always used at the root, so drop any active
context unless we are synchronously inside a loader function (genuine
nesting). A small depth counter (`runInsideLoaderFn`/`isInsideLoaderFn`)
keeps real nested calls working even when triggered from a component.

Closes #2684
@netlify

netlify Bot commented Jun 1, 2026

Copy link
Copy Markdown

Deploy Preview for vue-router canceled.

Name Link
🔨 Latest commit 57e834e
🔍 Latest deploy log https://app.netlify.com/projects/vue-router/deploys/6a1d626b0842110008b4893c

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c205135a-a39d-488f-9fa4-4fdbc7d656ed

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/data-loaders-nested-lazy-context-leak

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-new Bot commented Jun 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/vue-router@2727

commit: 57e834e

@codecov

codecov Bot commented Jun 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.55%. Comparing base (61f0e6b) to head (57e834e).
⚠️ Report is 6 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2727      +/-   ##
==========================================
+ Coverage   86.43%   86.55%   +0.11%     
==========================================
  Files          91       91              
  Lines       10395    10484      +89     
  Branches     2426     2438      +12     
==========================================
+ Hits         8985     9074      +89     
  Misses       1400     1400              
  Partials       10       10              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nested loader is called twice and has itself as a parent when parent loader resolves instantly

1 participant