Skip to content
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

fix inconsistent scroll restoration behavior #59366

Merged
merged 1 commit into from
Dec 7, 2023

Conversation

ztanner
Copy link
Member

@ztanner ztanner commented Dec 7, 2023

What?

While scrolled on a page, and when following a link to a new page and clicking the browser back button or using router.back(), the scroll position would sometimes restore scroll to the incorrect spot (in the case of the test added in this PR, it'd scroll you back to the top of the list)

Why?

The refactor in #56497 changed the way router actions are processed: specifically, all actions were assumed to be async, even if they could be handled synchronously. For most actions this is fine, as most are currently async. However, ACTION_RESTORE (triggered when the popstate event occurs) isn't async, and introducing a small amount of delay in the handling of this action can cause the browser to not properly restore the scroll position

How?

This special-cases ACTION_RESTORE to synchronously process the action and call setState when it's received, rather than creating a promise. To consistently reproduce this behavior, I added an option to our browser interface that'll allow us to programmatically trigger a CPU slowdown.

h/t to @alvarlagerlof for isolating the offending commit and sharing a minimal reproduction.

Closes NEXT-1819
Likely addresses #58899 but the reproduction was too complex to verify.

@ztanner
Copy link
Member Author

ztanner commented Dec 7, 2023

Current dependencies on/for this PR:

This stack of pull requests is managed by Graphite.

@ztanner ztanner force-pushed the 12-07-fix_inconsistent_scroll_restoration_behavior branch from 9a23b5b to aafce2b Compare December 7, 2023 13:53
@ijjk
Copy link
Member

ijjk commented Dec 7, 2023

Tests Passed

@ijjk
Copy link
Member

ijjk commented Dec 7, 2023

Stats from current PR

Default Build
General Overall increase ⚠️
vercel/next.js canary vercel/next.js 12-07-fix_inconsistent_scroll_restoration_behavior Change
buildDuration 10.9s 11.1s ⚠️ +195ms
buildDurationCached 6s 6.1s N/A
nodeModulesSize 199 MB 199 MB ⚠️ +2.43 kB
nextStartRea..uration (ms) 420ms 424ms N/A
Client Bundles (main, webpack)
vercel/next.js canary vercel/next.js 12-07-fix_inconsistent_scroll_restoration_behavior Change
170-HASH.js gzip 26.7 kB 26.7 kB N/A
199.HASH.js gzip 181 B 185 B N/A
3f784ff6-HASH.js gzip 53.3 kB 53.3 kB
framework-HASH.js gzip 45.2 kB 45.2 kB
main-app-HASH.js gzip 242 B 241 B N/A
main-HASH.js gzip 31.7 kB 31.7 kB N/A
webpack-HASH.js gzip 1.7 kB 1.7 kB N/A
Overall change 98.5 kB 98.5 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary vercel/next.js 12-07-fix_inconsistent_scroll_restoration_behavior Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary vercel/next.js 12-07-fix_inconsistent_scroll_restoration_behavior Change
_app-HASH.js gzip 195 B 194 B N/A
_error-HASH.js gzip 183 B 182 B N/A
amp-HASH.js gzip 501 B 501 B
css-HASH.js gzip 321 B 321 B
dynamic-HASH.js gzip 2.5 kB 2.5 kB N/A
edge-ssr-HASH.js gzip 255 B 255 B
head-HASH.js gzip 349 B 350 B N/A
hooks-HASH.js gzip 368 B 369 B N/A
image-HASH.js gzip 4.27 kB 4.27 kB N/A
index-HASH.js gzip 255 B 256 B N/A
link-HASH.js gzip 2.6 kB 2.6 kB N/A
routerDirect..HASH.js gzip 311 B 309 B N/A
script-HASH.js gzip 384 B 384 B
withRouter-HASH.js gzip 307 B 306 B N/A
1afbb74e6ecf..834.css gzip 106 B 106 B
Overall change 1.57 kB 1.57 kB
Client Build Manifests
vercel/next.js canary vercel/next.js 12-07-fix_inconsistent_scroll_restoration_behavior Change
_buildManifest.js gzip 483 B 483 B
Overall change 483 B 483 B
Rendered Page Sizes
vercel/next.js canary vercel/next.js 12-07-fix_inconsistent_scroll_restoration_behavior Change
index.html gzip 527 B 530 B N/A
link.html gzip 541 B 542 B N/A
withRouter.html gzip 523 B 525 B N/A
Overall change 0 B 0 B
Edge SSR bundle Size
vercel/next.js canary vercel/next.js 12-07-fix_inconsistent_scroll_restoration_behavior Change
edge-ssr.js gzip 93.5 kB 93.5 kB N/A
page.js gzip 146 kB 146 kB N/A
Overall change 0 B 0 B
Middleware size
vercel/next.js canary vercel/next.js 12-07-fix_inconsistent_scroll_restoration_behavior Change
middleware-b..fest.js gzip 622 B 625 B N/A
middleware-r..fest.js gzip 151 B 151 B
middleware.js gzip 37.4 kB 37.4 kB N/A
edge-runtime..pack.js gzip 1.92 kB 1.92 kB
Overall change 2.07 kB 2.07 kB
Next Runtimes
vercel/next.js canary vercel/next.js 12-07-fix_inconsistent_scroll_restoration_behavior Change
app-page-exp...dev.js gzip 168 kB 168 kB
app-page-exp..prod.js gzip 93.9 kB 93.9 kB
app-page-tur..prod.js gzip 94.7 kB 94.7 kB
app-page-tur..prod.js gzip 89.2 kB 89.2 kB
app-page.run...dev.js gzip 138 kB 138 kB
app-page.run..prod.js gzip 88.6 kB 88.6 kB
app-route-ex...dev.js gzip 24 kB 24 kB
app-route-ex..prod.js gzip 16.7 kB 16.7 kB
app-route-tu..prod.js gzip 16.7 kB 16.7 kB
app-route-tu..prod.js gzip 16.3 kB 16.3 kB
app-route.ru...dev.js gzip 23.4 kB 23.4 kB
app-route.ru..prod.js gzip 16.3 kB 16.3 kB
pages-api-tu..prod.js gzip 9.37 kB 9.37 kB
pages-api.ru...dev.js gzip 9.64 kB 9.64 kB
pages-api.ru..prod.js gzip 9.37 kB 9.37 kB
pages-turbo...prod.js gzip 21.9 kB 21.9 kB
pages.runtim...dev.js gzip 22.6 kB 22.6 kB
pages.runtim..prod.js gzip 21.9 kB 21.9 kB
server.runti..prod.js gzip 49.4 kB 49.4 kB
Overall change 930 kB 930 kB
Diff details
Diff for page.js

Diff too large to display

Diff for 170-HASH.js

Diff too large to display

Commit: b56d6c0

@ztanner ztanner force-pushed the 12-07-fix_inconsistent_scroll_restoration_behavior branch 2 times, most recently from 50d7dd3 to b1af0d0 Compare December 7, 2023 14:07
@ztanner ztanner marked this pull request as ready for review December 7, 2023 14:18
Comment on lines +739 to +740
// throttling the CPU to rule out flakiness based on how quickly the page loads
cpuThrottleRate: 6,

Choose a reason for hiding this comment

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

Nice to see this making it all the way to the test. Could potentially be interesting to turn this on for some other tests once to see if any of them break unexpectedly.

@ztanner ztanner force-pushed the 12-07-fix_inconsistent_scroll_restoration_behavior branch from b1af0d0 to b56d6c0 Compare December 7, 2023 14:24
startTransition(() => {
// we immediately notify React of the pending promise -- the resolver is attached to the action node
// and will be called when the associated action promise resolves
setState(deferredPromise)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm confused, where is the setState if this is an ACTION_RESTORE action?

Copy link
Member Author

@ztanner ztanner Dec 7, 2023

Choose a reason for hiding this comment

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

This is initialized to setState here:

} = { resolve: setState, reject: () => {} }

And called in the action runner:

@ztanner ztanner merged commit a578cc8 into canary Dec 7, 2023
70 checks passed
@ztanner ztanner deleted the 12-07-fix_inconsistent_scroll_restoration_behavior branch December 7, 2023 19:17
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 22, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants