* fix(#35286): reset visible state when image src changed
* fix(#35286): reset visible state when link href changed
* test(image): image with new src should be re-lazyloaded
* test: apply code suggestions from @styfle's review
* test: incorrect condition of image load check
Fixed lazyRoot functionality (#33290). Changed the unique id for Intersection Observers discrimination since previously they were only identified by the different rootMargins, now each being identified by the rootMargin and the root element as well
Added more Images to the test with different margins and with/without lazyRoot prop. Browser correctly initially loading two of the four Images according to the props' specifications.
Co-authored-by: Steven <steven@ceriously.com>
* Added 'rootEl' oprional property to next/Image component resembling 'root' option of the Intersection Observer API
* changed 'rootEl' to 'lazyBoundary' and its type as well
* added test, fixed initial root detection
* Update test/integration/image-component/default/test/index.test.js
Co-authored-by: Steven <steven@ceriously.com>
* prop names changed
* added 'lazyroot' prop to the documentation
* removed unused import
* Apply suggestions from code review
* Update docs with lazyRoot added in 12.0.9
Co-authored-by: Steven <steven@ceriously.com>
This pull request adds an `elements.delete` operation to the `useIntersection`'s cleanup function: `unobserve`.
Without this delete operation, next.js holds onto an unreachable reference of every observed element indefinitely (automatically every Link and Image is observed, so that means every rendered Link and Image element adds to the leak). I found this memory leak when building out an infinite feed in next.js with thousands of Link elements.
The final code block of the `unobserve` function body:
```tsx
// Destroy observer when there's nothing left to watch:
if (elements.size === 0) {
observer.disconnect()
observers.delete(id)
}
```
Is effectively unreachable without this delete operation, as the `elements` map will never decrease in size as it is currently. This means that there will always be at least one IntersectionObserver instance in memory if useIntersection has been used once, regardless of if there are currently any components still using the hook.
This pull request completely replaces our old page loader with a brand new route loader.
Our existing comprehensive test suite means I did not need to add a bunch of tests. I did add them where behavior was added or fixed.
Summary of the changes:
- Eagerly evaluates prefetched pages in browser idle time (speeds up transitions)
- Router is **no longer frozen** indefinitely if the Build Manifest never arrives
- Router is **no longer frozen** indefinitely if a page fails to bootstrap
- New `withFuture` utility instead of ad-hoc deduping per resource
- Prefetching is now delayed until browser idle time to not impact TTI
- Browsers without `prefetch` now fall back to eager evaluation instead of using `preload`
- We're now ready to serve non-static assets **with `no-store` without breaking prefetching**
- **Application can now hydrate without fetching CSS assets—this is a huge performance win that was previously blocking hydration**
---
The minor size increase here is unfortunate, but we have to incur it for correctness.
---
Fixes#18389Fixes#18642
This pull request fixes `<Image />` not updating when new props are passed by removing external DOM mutations and relying on React to do it instead.
As an added bonus, I've extracted the intersection observer from both the `<Image />` and `<Link />` component, as their instance can be shared!
The increase in size is minor (+3B), and actually a decrease for apps using both `<Image />` and `<Link />`.
---
Fixes#18698Fixes#18369