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

Added CROSSORIGIN and eagerness PRERENDER #434

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "quicklink",
"version": "2.3.0",
"version": "2.4.0",
"description": "Faster subsequent page-loads by prefetching in-viewport links during idle time",
"repository": {
"type": "git",
Expand Down Expand Up @@ -71,4 +71,4 @@
"size-limit": "^11.1.4",
"uvu": "^0.5.6"
}
}
}
4 changes: 2 additions & 2 deletions src/chunks.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
**/

import throttle from 'throttles';
import {priority, supported} from './prefetch.mjs';
import {viaFetch, supported} from './prefetch.mjs';
import requestIdleCallback from './request-idle-callback.mjs';

// Cache of URLs we've prefetched
Expand Down Expand Up @@ -145,7 +145,7 @@ export function prefetch(url, isPriority) {
// ~> so that we don't repeat broken links
toPrefetch.add(str);

return (isPriority ? priority : supported)(
return (isPriority ? viaFetch : supported)(
new URL(str, location.href).toString(),
);
}),
Expand Down
26 changes: 16 additions & 10 deletions src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
**/

import throttle from 'throttles';
import {priority, supported} from './prefetch.mjs';
import {supported, viaFetch} from './prefetch.mjs';
import requestIdleCallback from './request-idle-callback.mjs';
import {addSpeculationRules, hasSpecRulesSupport} from './prerender.mjs';

Expand Down Expand Up @@ -72,6 +72,8 @@ function checkConnection(conn) {
* @param {Object} options - Configuration options for quicklink
* @param {Object|Array} [options.el] - DOM element(s) to prefetch in-viewport links of
* @param {Boolean} [options.priority] - Attempt higher priority fetch (low or high)
* @param {Boolean} [options.checkAccessControlAllowOrigin] - Check Access-Control-Allow-Origin response header
* @param {Boolean} [options.checkAccessControlAllowCredentials] - Check the Access-Control-Allow-Credentials response header
* @param {Array} [options.origins] - Allowed origins to prefetch (empty allows all)
* @param {Array|RegExp|Function} [options.ignores] - Custom filter(s) that run after origin checks
* @param {Number} [options.timeout] - Timeout after which prefetching will occur
Expand Down Expand Up @@ -147,7 +149,8 @@ export function listen(options = {}) {
// Do not prefetch if will match/exceed limit and user has not switched to shouldOnlyPrerender mode
if (toPrefetch.size < limit && !shouldOnlyPrerender) {
toAdd(() => {
prefetch(hrefFn ? hrefFn(entry) : entry.href, options.priority)
prefetch(hrefFn ? hrefFn(entry) : entry.href, options.priority,
options.checkAccessControlAllowOrigin, options.checkAccessControlAllowCredentials)
.then(isDone)
.catch(error => {
isDone();
Expand All @@ -156,7 +159,7 @@ export function listen(options = {}) {
});
}
}, delay);
// On exit
// On exit
} else {
entry = entry.target;
const index = hrefsInViewport.indexOf(entry.href);
Expand All @@ -172,9 +175,9 @@ export function listen(options = {}) {
timeoutFn(() => {
// Find all links & Connect them to IO if allowed
const elementsToListen = options.el &&
options.el.length &&
options.el.length > 0 &&
options.el[0].nodeName === 'A' ?
options.el.length &&
options.el.length > 0 &&
options.el[0].nodeName === 'A' ?
options.el :
(options.el || document).querySelectorAll('a');

Expand All @@ -201,10 +204,13 @@ export function listen(options = {}) {
/**
* Prefetch a given URL with an optional preferred fetch priority
* @param {String} url - the URL to fetch
* @param {Boolean} [isPriority] - if is "high" priority
* @param {Boolean} isPriority - if is "high" priority
* @param {Boolean} checkAccessControlAllowOrigin - true to set crossorigin="anonymous" for DOM prefetch
* and mode:'cors' for API fetch
* @param {Boolean} checkAccessControlAllowCredentials - true to set credentials:'include' for API fetch
* @return {Object} a Promise
*/
export function prefetch(url, isPriority) {
export function prefetch(url, isPriority, checkAccessControlAllowOrigin, checkAccessControlAllowCredentials) {
const chkConn = checkConnection(navigator.connection);
if (chkConn instanceof Error) {
return Promise.reject(new Error(`Cannot prefetch, ${chkConn.message}`));
Expand All @@ -223,8 +229,8 @@ export function prefetch(url, isPriority) {
// ~> so that we don't repeat broken links
toPrefetch.add(str);

return (isPriority ? priority : supported)(
new URL(str, location.href).toString(),
return (isPriority ? viaFetch : supported)(
new URL(str, location.href).toString(), checkAccessControlAllowOrigin, checkAccessControlAllowCredentials, isPriority,
);
}),
);
Expand Down
28 changes: 21 additions & 7 deletions src/prefetch.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
/**
* Checks if a feature on `link` is natively supported.
* Examples of features include `prefetch` and `preload`.
* @param {Object} link Link object.
* @param {Object} link - Link object.
* @return {Boolean} whether the feature is supported
*/
function hasPrefetch(link) {
Expand All @@ -31,13 +31,17 @@
/**
* Fetches a given URL using `<link rel=prefetch>`
* @param {string} url - the URL to fetch
* @param {Boolean} hasCrossorigin - true to set crossorigin="anonymous"
* @return {Object} a Promise
*/
function viaDOM(url) {
function viaDOM(url, hasCrossorigin) {
return new Promise((resolve, reject, link) => {
link = document.createElement('link');
link.rel = 'prefetch';
link.href = url;
if (hasCrossorigin) {
link.setAttribute('crossorigin', 'anonymous');
}

link.onload = resolve;
link.onerror = reject;
Expand All @@ -49,13 +53,16 @@
/**
* Fetches a given URL using XMLHttpRequest
* @param {string} url - the URL to fetch
* @param {Boolean} hasCredentials - true to set withCredentials:true
* @return {Object} a Promise
*/
function viaXHR(url) {
function viaXHR(url, hasCredentials) {
return new Promise((resolve, reject, request) => {
request = new XMLHttpRequest();

request.open('GET', url, request.withCredentials = true);
request.open('GET', url, request.withCredentials = hasCredentials);

request.setRequestHeader('Accept', '*/*');

request.onload = () => {
if (request.status === 200) {
Expand All @@ -74,17 +81,24 @@
* Fetches a given URL using the Fetch API. Falls back
* to XMLHttpRequest if the API is not supported.
* @param {string} url - the URL to fetch
* @param {Boolean} hasModeCors - true to set mode:'cors'
* @param {Boolean} hasCredentials - true to set credentials:'include'
* @param {Boolean} isPriority - true to set priority:'high'
* @return {Object} a Promise
*/
export function priority(url) {
export function viaFetch(url, hasModeCors, hasCredentials, isPriority) {
// TODO: Investigate using preload for high-priority
// fetches. May have to sniff file-extension to provide
// valid 'as' values. In the future, we may be able to
// use Priority Hints here.
//
// As of 2018, fetch() is high-priority in Chrome
// and medium-priority in Safari.
return window.fetch ? fetch(url, {credentials: 'include'}) : viaXHR(url);
options = {headers: {accept: '*/*'}};

Check warning

Code scanning / CodeQL

Missing variable declaration Warning

Variable options is used like a local variable, but is missing a declaration.
Copy link
Author

Choose a reason for hiding this comment

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

I have updated the declaration for the variable, defining it as a constant using the const keyword.

if (!hasModeCors) options.mode = 'no-cors';
if (hasCredentials) options.credentials = 'include';
isPriority ? options.priority = 'high' : options.priority = 'low';
return window.fetch ? fetch(url, options) : viaXHR(url, hasCredentials);
}

export const supported = hasPrefetch() ? viaDOM : viaXHR;
export const supported = hasPrefetch() ? viaDOM : viaFetch;
Loading