-
Notifications
You must be signed in to change notification settings - Fork 417
Improve speculation rules handling based on element visibility #446
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
base: main
Are you sure you want to change the base?
Changes from 6 commits
cfc3131
cca4482
cd356d3
c5c207a
2fca1ac
722a2c1
5a23943
ce1b428
32cbfc9
11e09f3
1365d4e
26cb955
b6c8eb1
74f0f80
357bd84
a5fbc53
ad37202
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -17,7 +17,7 @@ | |||
import throttle from 'throttles'; | ||||
import {prefetchOnHover, supported, viaFetch} from './prefetch.mjs'; | ||||
import requestIdleCallback from './request-idle-callback.mjs'; | ||||
import {addSpeculationRules, hasSpecRulesSupport} from './prerender.mjs'; | ||||
import {addSpeculationRules, removeSpeculationRule, hasSpecRulesSupport} from './prerender.mjs'; | ||||
|
||||
// Cache of URLs we've prefetched | ||||
// Its `size` is compared against `opts.limit` value. | ||||
|
@@ -102,6 +102,7 @@ export function listen(options = {}) { | |||
const ignores = options.ignores || []; | ||||
const delay = options.delay || 0; | ||||
const hrefsInViewport = []; | ||||
specRulesInViewport = new Map(); | ||||
|
||||
const timeoutFn = options.timeoutFn || requestIdleCallback; | ||||
const hrefFn = typeof options.hrefFn === 'function' && options.hrefFn; | ||||
|
@@ -131,19 +132,26 @@ export function listen(options = {}) { | |||
// Do not prefetch if not found in viewport | ||||
if (!hrefsInViewport.includes(entry.href)) return; | ||||
|
||||
observer.unobserve(entry); | ||||
giorgiopellegrino marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
if (!shouldOnlyPrerender && !shouldPrerenderAndPrefetch) observer.unobserve(entry); | ||||
giorgiopellegrino marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
|
||||
// prerender, if.. | ||||
// either it's the prerender + prefetch mode or it's prerender *only* mode | ||||
// Prerendering limit is following options.limit. UA may impose arbitraty numeric limit | ||||
if ((shouldPrerenderAndPrefetch || shouldOnlyPrerender) && toPrerender.size < limit) { | ||||
prerender(hrefFn ? hrefFn(entry) : entry.href, options.eagerness).catch(error => { | ||||
if (options.onError) { | ||||
options.onError(error); | ||||
} else { | ||||
throw error; | ||||
} | ||||
}); | ||||
// The same URL is not already present as a speculation rule | ||||
if ((shouldPrerenderAndPrefetch || shouldOnlyPrerender) && toPrerender.size < limit && !specRulesInViewport.has(entry.href)) { | ||||
prerender(hrefFn ? hrefFn(entry) : entry.href, options.eagerness) | ||||
.then(specMap => { | ||||
for (const [key, value] of specMap) { | ||||
specRulesInViewport.set(key, value); | ||||
} | ||||
}) | ||||
.catch(error => { | ||||
if (options.onError) { | ||||
options.onError(error); | ||||
} else { | ||||
throw error; | ||||
} | ||||
}); | ||||
|
||||
return; | ||||
} | ||||
|
@@ -168,6 +176,9 @@ export function listen(options = {}) { | |||
if (index > -1) { | ||||
hrefsInViewport.splice(index); | ||||
} | ||||
if (specRulesInViewport.has(entry.href)) { | ||||
specRulesInViewport = removeSpeculationRule(specRulesInViewport, entry.href); | ||||
} | ||||
} | ||||
}); | ||||
}, { | ||||
|
@@ -245,6 +256,8 @@ export function prefetch(urls, isPriority, checkAccessControlAllowOrigin, checkA | |||
* @return {Object} a Promise | ||||
*/ | ||||
export function prerender(urls, eagerness = 'immediate') { | ||||
urls = [].concat(urls); | ||||
|
||||
Comment on lines
+261
to
+262
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder why this is necessary? Is it to create a copy to so that if the underlying object is modified during some async iteration to prevent unexpected behavior? I don't see this as being the case, since this is not an async function and below it just loops over the I think this can just be removed.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hello @westonruter , There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @westonruter, this line was already present in the existing Speculation Rules implementation, so not really related to this PR. It was done this way to ensure that URLs would be treated as array of strings. @giorgiopellegrino to follow up in case an action is needed |
||||
const chkConn = checkConnection(navigator.connection); | ||||
if (chkConn instanceof Error) { | ||||
return Promise.reject(new Error(`Cannot prerender, ${chkConn.message}`)); | ||||
|
@@ -258,7 +271,7 @@ export function prerender(urls, eagerness = 'immediate') { | |||
return Promise.reject(new Error('This browser does not support the speculation rules API. Falling back to prefetch.')); | ||||
} | ||||
|
||||
for (const url of [].concat(urls)) { | ||||
for (const url of urls) { | ||||
toPrerender.add(url); | ||||
} | ||||
|
||||
|
@@ -267,6 +280,6 @@ export function prerender(urls, eagerness = 'immediate') { | |||
console.warn('[Warning] You are using both prefetching and prerendering on the same document'); | ||||
} | ||||
|
||||
const addSpecRules = addSpeculationRules(toPrerender, eagerness); | ||||
return addSpecRules === true ? Promise.resolve() : Promise.reject(addSpecRules); | ||||
const specMap = addSpeculationRules(urls, eagerness); | ||||
return specMap.size > 0 ? Promise.resolve(specMap) : Promise.reject(specMap); | ||||
} |
Uh oh!
There was an error while loading. Please reload this page.