Add opt-in Turbo Frame prefetching on hover - #30
Open
manuelpuyol wants to merge 2 commits into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
Adds opt-in hover prefetching with frame-aware caching, lifecycle events, metrics, documentation, and functional coverage.
Changes:
- Adds delayed per-link prefetching and response reuse.
- Exposes prefetch lifecycle events and waste reasons.
- Adjusts head rendering, progress-bar updates, and scroll handling.
Show a summary per file
| File | Description |
|---|---|
README.md |
Documents hover prefetching. |
src/core/drive/form_submission.ts |
Clears prefetches on mutations. |
src/core/drive/page_renderer.ts |
Preserves React-managed head elements. |
src/core/drive/prefetch_cache.ts |
Implements the prefetch cache. |
src/core/drive/progress_bar.ts |
Uses a CSS scale variable. |
src/core/frames/frame_controller.ts |
Exposes frame fetch responses during rendering. |
src/core/index.ts |
Exports prefetch event types. |
src/core/session.ts |
Integrates the prefetch observer. |
src/core/view.ts |
Adds render fetch-response context. |
src/http/fetch_request.ts |
Supports prefetched response reuse. |
src/observers/link_prefetch_observer.ts |
Implements hover prefetching. |
src/observers/scroll_observer.ts |
Throttles scroll updates. |
src/tests/fixtures/hover_to_prefetch.html |
Provides prefetch test links. |
src/tests/fixtures/test.js |
Logs prefetch events. |
src/tests/functional/link_prefetch_observer_tests.ts |
Tests prefetch behavior and metrics. |
src/tests/unit/export_tests.ts |
Verifies exported prefetch types. |
Review details
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Files reviewed: 16/16 changed files
- Comments generated: 5
- Review effort level: Balanced
| this.delegate.requestStarted(this) | ||
| const response = await fetch(this.url.href, fetchOptions) | ||
|
|
||
| this.response = event.detail.fetchRequest?.response || fetch(this.url.href, fetchOptions) |
| const fetchEvent = event as TurboBeforeFetchRequestEvent | ||
| const { fetchOptions, url } = fetchEvent.detail | ||
|
|
||
| if (fetchEvent.target instanceof HTMLFormElement || fetchOptions.method !== "GET") return |
Comment on lines
+213
to
+216
| const frame = link.closest("turbo-frame") | ||
| const target = link.getAttribute("data-turbo-frame") || frame?.getAttribute("target") || frame?.id | ||
|
|
||
| return target && target !== "_top" ? target : null |
Comment on lines
+35
to
+38
| requestAnimationFrame(() => { | ||
| this.scrollScheduled = false | ||
| this.updatePosition({ x: window.pageXOffset, y: window.pageYOffset }) | ||
| }) |
|
|
||
| removeCurrentHeadProvisionalElements() { | ||
| for (const element of this.currentHeadProvisionalElements) { | ||
| if (isManagedByReact(element)) continue |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add per-link, opt-in hover prefetching for Turbo navigation, including links that target Turbo Frames.
Unmarked links do not create a timer, cache entry, lifecycle event, or additional network request. Prefetching defaults to a 100 ms hover delay;
data-turbo-prefetch-delayoverrides it for an individual link.Implementation
data-turbo-frame, the closest frame target, or the closest frame ID and send the matchingTurbo-Frameheader._topremains a full-page request.data-turbo="false"links.turbo:before-prefetchas a cancelable application hook.Observability
Dispatch correlated lifecycle events so consumers can calculate effectiveness:
turbo:prefetch-startturbo:prefetch-hitturbo:prefetch-wasteEach event includes an ID, URL, resolved frame, and configured delay. Hit and waste events include duration; waste events also include a reason. Hit rate is
hits / starts, and waste rate iswastes / starts. A hover canceled before its delay is excluded because no request started.Existing GitHub patches
The first commit ports the current
github-uipatch-package behavior into source so a release from this branch can replace that downstream patch. It preserves frame fetch responses in render hooks, React-managed head elements, compositor-driven progress values with a standalone CSS fallback, and animation-frame-coalesced scroll reads.Validation
yarn buildyarn lintThe legacy Intern runner could not execute in this container because its configured Firefox/ChromeDriver environment was unavailable; it ran zero tests.