Skip to content

Commit

Permalink
Correctly Dedupe Prefetching (#10758)
Browse files Browse the repository at this point in the history
* Correctly Dedupe Prefetching

* add test
  • Loading branch information
Timer committed Feb 29, 2020
1 parent b7f7790 commit 24345c9
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 9 deletions.
31 changes: 22 additions & 9 deletions packages/next/client/link.tsx
Expand Up @@ -57,7 +57,7 @@ let observer: IntersectionObserver
const listeners = new Map()
const IntersectionObserver =
typeof window !== 'undefined' ? (window as any).IntersectionObserver : null
const prefetched: { [href: string]: boolean } = {}
const prefetched: { [cacheKey: string]: boolean } = {}

function getObserver() {
// Return shared instance of IntersectionObserver if already created
Expand Down Expand Up @@ -139,10 +139,16 @@ class Link extends Component<LinkProps> {
}

handleRef(ref: Element) {
const isPrefetched = prefetched[this.getPaths()[0]]
if (this.p && IntersectionObserver && ref && ref.tagName) {
this.cleanUpListeners()

const isPrefetched =
prefetched[
this.getPaths().join(
// Join on an invalid URI character
'%'
)
]
if (!isPrefetched) {
this.cleanUpListeners = listenToIntersections(ref, () => {
this.prefetch()
Expand Down Expand Up @@ -208,17 +214,24 @@ class Link extends Component<LinkProps> {
prefetch(options?: PrefetchOptions) {
if (!this.p || typeof window === 'undefined') return
// Prefetch the JSON page if asked (only in the client)
const [href, asPath] = this.getPaths()
const paths = this.getPaths()
// We need to handle a prefetch error here since we may be
// loading with priority which can reject but we don't
// want to force navigation since this is only a prefetch
Router.prefetch(href, asPath, options).catch(err => {
if (process.env.NODE_ENV !== 'production') {
// rethrow to show invalid URL errors
throw err
Router.prefetch(paths[/* href */ 0], paths[/* asPath */ 1], options).catch(
err => {
if (process.env.NODE_ENV !== 'production') {
// rethrow to show invalid URL errors
throw err
}
}
})
prefetched[href] = true
)
prefetched[
paths.join(
// Join on an invalid URI character
'%'
)
] = true
}

render() {
Expand Down
11 changes: 11 additions & 0 deletions test/integration/preload-viewport/pages/not-de-duped.js
@@ -0,0 +1,11 @@
import Link from 'next/link'

export default () => {
return (
<p>
<Link href="/first" as="/first#different">
<a>to /first</a>
</Link>
</p>
)
}
16 changes: 16 additions & 0 deletions test/integration/preload-viewport/test/index.test.js
Expand Up @@ -228,4 +228,20 @@ describe('Prefetching Links in viewport', () => {
const calledPrefetch = await browser.eval(`window.calledPrefetch`)
expect(calledPrefetch).toBe(false)
})

it('should prefetch with a different asPath for a prefetched page', async () => {
// info: both `/` and `/not-de-duped` ref the `/first` page, which we want
// to see prefetched twice.
const browser = await webdriver(appPort, '/')
await browser.eval(`(function() {
window.calledPrefetch = false
window.next.router.prefetch = function() {
window.calledPrefetch = true
}
window.next.router.push('/not-de-duped')
})()`)
await waitFor(2 * 1000)
const calledPrefetch = await browser.eval(`window.calledPrefetch`)
expect(calledPrefetch).toBe(true)
})
})

0 comments on commit 24345c9

Please sign in to comment.