googlechromelabs / quicklink Goto Github PK
View Code? Open in Web Editor NEW⚡️Faster subsequent page-loads by prefetching in-viewport links during idle time
Home Page: https://getquick.link
License: Apache License 2.0
⚡️Faster subsequent page-loads by prefetching in-viewport links during idle time
Home Page: https://getquick.link
License: Apache License 2.0
Maybe set a guard to prefetch urls with the same domain?
Because now either XHR or Fetch will fail for external links
https://unpkg.com/[email protected]/dist/quicklink.umd.js
You can open this link and verify it by search
For example, these three URLs are all equivalent:
https://www.google.com
https://www.google.com/
https:\\www.google.com/
(That last one is an extreme example, but it’s pretty common to see the first and second variation used interchangeably.)
When reading an element’s .href
like in
Line 25 in f9a2ca7
https://www.google.com/
However, the same normalization is not applied when the user manually passes in URLs:
Line 67 in f9a2ca7
Because of this, the toPrefetch
set currently ends up with three separate entries in this case, even though all of them normalize to the same URL:
quicklink({
urls: [
'https://www.google.com',
'https://www.google.com/',
'https:\\www.google.com/',
],
});
It can be solved by forcing URL normalization before calling prefetcher
on this line:
Line 67 in f9a2ca7
- options.urls.forEach(prefetcher);
+ options.urls.forEach(url => prefetcher(new URL(url).toString()));
First thank you for this nice plugin.
Something that could improve it is an option to ignore all link that redirect outside of the current website.
It could be done with a new option to ignore link href with target="_blank"
Cheers
It is difficult to hack on this plugin on an existing WordPress development environment. For example, Gutenberg, AMP, and PWA plugins all can just be cloned into wp-content/plugins
of any existing WordPress install and then with npm install
and npm run build
they can be activated in-place.
Can that be implemented for Quicklink as well? Part of this would include making setup-local-env.sh
optional.
Not sure it is a bug but i found the api to be misleading:
I expect the ignore configuration to filter the links to observe and so to limit to the survivors the "in viewport" mechanism.
It seems to be not exactly the case: any links sharing the same url that a link that was not ignore by the configuration will be observed.
For example, I used the ignore function receiving an element (uri, elem) => {...} to apply prefetching mechanism only on link having a specific attribute.
So it allows me to decide which link should be prefetching by adding a dedicated attribute.
On my page I have 2 links redirecting to the very same url.
The first one is in my header (not visible by default) and the second one is in my footer.
I decided to put my prefetching attribute only on the link in the footer.
But reloading the page, the prefetching is always done even if my footer link is not in the viewport because the link in the header (having not the dedicated attribute and so that should have be ignored) has the same url...
I could force my intended behavior by specifying a region to observe (the footer) but it adds some complexity and code more difficult to maintain.
So I expect a link that doesn't survive the ignore test to not be observed
Will folks want to pass customizations for rootMargin
, threshold
etc? Perhaps. We could enable setting this via options.
Sorry for my innocence but can someone tell me what is the .mjs file?
Can you ignore specific elements? "Quicklink everything but [...]" case
These are already deployed with before/afters on WebPageTest. Just need to decide whether to include them in the README or wiki.
I added quicklink to a play project of mine, https://ionic.zone.
On https://ionic.zone/content, I have a table of contents with loads of page internal links with an anchor (#anchor
) to headlines below. It looks like quicklinks tried to preload all of those:
Wouldn't it make sense to not preload links to the page I am already viewing?
Hello, this looks like a very handy library. However, I'm having trouble using it without using it as an ES-module.
My source code:
<script src="https://unpkg.com/[email protected]/dist/quicklink.js"></script>
<script>
quicklink();
</script>
The output:
quicklink.js:1 Uncaught ReferenceError: module is not defined
at quicklink.js:1
(anonymous) @ quicklink.js:1
(index):142 Uncaught ReferenceError: quicklink is not defined
at (index):142
Expected result
I would expect it to work since the readme says so.
It would be nice to limit the number of links that will be prefetched
which can also default at a sane number.
Proposed API: options.limit
Would love to get your feedback on naming & default limit
From Chrome metrics:
We don't have a platform way to expose network idle just yet, but the service worker approach should be reasonably reliable (but comes with the overhead of requiring a serviceworker, obviously).
re: https://github.com/pastelsky/network-idle-callback
If I implemented support for this, we could either do it as a default (downside: requires everyone to use Service Workers) or we make it a suggested option.
The unpgk link (https://unpkg.com/quicklink) in the readme is not working.
Feedback from @surma:
I feel like by default you should add a rootMargin to the IO to trigger the load before something comes into the viewport.
So, rootMargin
defaults to "0px 0px 0px 0px", meaning the intersection will be computed between the root element's unmodified bounds rectangle and the target's bounds. This change would be made to https://github.com/GoogleChromeLabs/quicklink/blob/master/src/index.mjs#L21
I just recently launched a new web site that uses quicklink. It's impressive, and improves the perception of speed to a point where a static website feels almost like an SPA at times. Good work!
One thing I noticed, though, is that quicklink crashes when Intersection Observer is not available. I'm aware that the documentation recommends a polyfill, but do you think it would make sense to fail softly when Intersection Observer is unavailable? Perhaps using this check and using console.warn
?
In any event, great work on this. This script has tremendous utility in improving perceived performance, and I look forward to using it in future projects.
It would be nice to customize IntersectionObserve constructor option.
Proposed API: options.observerOptions.
Would like to get your feedback on naming and ready to take a PR if needed
https://github.com/glixlur/snap
Prefetch on hover
Just a thought
In the Idle-Until-Urgent (IUU) pattern you delay loading a resource using requestIdleCallback
(or similar). But when a resource becomes urgent, you short-circuit rIC and load it immediately.
AFAIU, quicklink is supposed to use Intersection Observer to determine when a resource becomes urgent. The current code, however, only start observing elements in rIC. Those two need to get decoupled.
Happy to take this once #9 lands.
I added quicklink to a Chrome extension I have. The thing is, all of my links have the target="_blank" attribute, because that's the only way to open up links from the extension popup (otherwise, you click on them and nothing happens).
So far it's adding the correctly for each of links, but I don't notice a speed improvement when I click on them.
My question is: is it possible that when a prefetch link is opened in a different tab, the browser simply forgets the fetching?
It seems the error is from the module.export in the network idle callback loaded from unpkg
(https://unpkg.com/[email protected]/lib/index.js)
Thank you for such a nice library :)
One of the links which are visible on my website is /logout
link. As you can imagine this link log me out from the web application. Is there ability to exclude that link from being prefetched 😄?
As it doesn't use Event.preventDefault(), it should use the passive boolean to save a few cpu time.
cf: https://developers.google.com/web/tools/lighthouse/audits/passive-event-listeners
I am less sure, but quicklink() is called once and if there is a full reload, the addeventlistener is redownloaded.
So the once boolean should be used ? (it will automatically remove the listerner after it as been called once.
cf: https://developers.google.com/web/updates/2016/10/addeventlistener-once
So the readme should have:
window.addEventListener('load', {passive: true, once: true}, () =>{
quicklink();
});
(I may be wrong !)
Could we add a link in Readme to provide a cdn version quicklink ? The polyfills is built on polyfill-service, so it is dynamic.
Here is the link:
https://b.alicdn.com/s/static/sdk?sdks=quicklink/1.0.0/index.umd.js&polyfills=IntersectionObserver,Set,Array.from
So, I've been having some fun with this over the past couple of days - everything is fine and dandy in Chrome - I'm yet to test other browsers such as Safari and Firefox!
However on IE11, as soon as I call quicklink();
(after polyfilling!) IE just stops completely.
Any ideas/pointers as to where I'm going wrong!
//This function is called if InterserctionObserver is not natively
//supported by the browser. The function takes 1 argument - URL.
//It is at this point that we polyfill the feature using polyfill.io
//based on the URL checkIntersectionObserver passes on line 49.
function loadIntersectionObserver(url) {
return new Promise(function(resolve, reject) {
var script = document.createElement('script');
script.src = url;
document.getElementsByTagName('body')[0].appendChild(script);
console.log('Grabbing IntersectionObserver polyfill from: ', script.src);
script.onload = resolve;
script.onerror = reject;
});
}
function loadquicklink() {
return new Promise(function(resolve, reject) {
var qlscript = document.createElement('script');
qlscript.src = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/quicklink.umd.js';
qlscript.defer = true;
document.getElementsByTagName('body')[0].appendChild(qlscript);
console.log('Grabbing quicklink JS!')
qlscript.onload = resolve;
qlscript.onerror = reject;
});
}
//This function checks whether we need to polyfill IntersectionObserver or not
//If we don't, we can use the native API. If we do need to, then we go to the
//loadIntersectionObserver function to polyfill the functionality.
function checkIntersectionObserver() {
if (
'IntersectionObserver' in window &&
'IntersectionObserverEntry' in window
) {
console.log( 'Nice one - your browser supports IntersectionObserver. No polyfills necessary!' );
return loadquicklink();
} else {
console.log( "Ahhh, your browser doesn't support IntersectionObserver. I'm gonna have to polyfill it so stuff works. Hang on one sec!" );
return loadIntersectionObserver(
'https://polyfill.io/v2/polyfill.js?features=IntersectionObserver&callback=loadquicklink'
);
}
}
window.onload = function quicklinkloaded() {
checkIntersectionObserver().then(
function() {
console.log( 'Aha! Everything is ready! Calling quicklink to get potential future pages ready for you to visit in advance!' );
quicklink();
console.log( "Et voila! We're now prefetching things you might click on - hopefully that speeds things up for you!!!" );
},
function() {
console.log( "So there was an issue polyfilling IntersectionObserver, which means that I can't preload future pages for you. Sorry! :(" );
console.log( "If you want this to work, I'd recommend upgrading to a browser that supports IntersectionObserver natively. You can find out which browsers do by visting: https://caniuse.com/#feat=intersectionobserver" );
}
);
}
Note: Please excuse my messy code - this one is a learning curve for me and I'm fairly new to JS :)
I am wondering why there is no chrome plugin that would load this on any page? Am I overseeing something?
Hi, I'm having an issue with quicklinks.umd when using tel links. When a tel link is used the console error is then produced:
net::ERR_UNKNOWN_URL_SCHEME
I've tried using the ignores but I just can't get it to not include tel or mailto links.
<script id="quicklink">
window.addEventListener('load', () =>{
quicklink({
timeout: 4000,
ignores: [
/tel:/g,
/#(.+)/,
uri => uri.includes('tel:')
(uri, elem) => elem.hasAttribute('noprefetch')
]
});
});
</script>
I just can't seem to figure it out. Any help would be appricated. Thanks
First I tried this to exclude a element:
const elem = document.querySelectorAll(':not(.post-copyright-link)');
But I got this error:
Uncaught TypeError: e.el.querySelectorAll is not a function
So I put code into ignores, here's all my script:
<script src="dist/quicklink.umd.js"></script>
<script>
window.addEventListener('load', () => {
const elem = document;
quicklink({
el: elem,
priority: true,
ignores: [
uri => uri.includes('#'),
uri => uri.includes('.xml'),
(uri, elem) => elem.querySelector('li.post-copyright-link')
]
});
});
</script>
There's no error but still fetch ignored URL in li.post-copyright-link, how can I solve it ?
Heyo..
This looks super neat.
I'd like to be able to use this alongside something like barba.js to handle page transitions.
If I add an event listener to all of my links, would there be a way of checking to see if the url has already been downloaded, and if so trigger the page transition, and update the dom, without having to make another xhr request?
function onClick(e) {
// magic code
if(cached(e)) {
startAnimation(cached(e).html)
return
}
fetch(e.pathname).then(etc => etc(etc)).then((html) => startAnimation(html))
}
any thoughts?
thanks
Currently the readme suggests to include the script into the page via:
<!-- Include quicklink from dist -->
<script src="dist/quicklink.umd.js"></script>
<!-- Initialize (you can do this whenever you want) -->
<script>
quicklink();
</script>
or at load
event via:
<script>
window.addEventListener('load', () =>{
quicklink();
});
</script>
However, shouldn't the quicklink.umd.js
script be loaded with async
to begin with? The blocking script is not good for performance.
Ideally you should be able to do something like this, similar to the AMP shadow doc API:
<script async src="dist/quicklink.umd.js"></script>
<script>
(window.quicklink = window.quicklink || []).push(function(quicklink) {
quicklink();
});
// Or...
window.addEventListener('load', () =>{
(window.quicklink = window.quicklink || []).push(function(quicklink) {
quicklink();
});
});
</script>
Doing a quick and dirty test of this library on my personal site, I have noticed that (possibly large) zip download files are being fetched, too... it would be interesting to be able to restrict which kind of URLs would be fetched.
Per the discussion here: #43.
For dynamic content, depending on the page structure the query options.el.querySelector('a')
, could return links that were already observed/prefetched and now unobserved (thanks to #51).
I provided a couple of options here: #43 (comment)
Hello,
I just realized something after noticing a "bug" on my site using Laravel:
The pages of the site using the library "pre-load", the php sessions record this load and propel unwanted behaviors.
For example, Laravel's back()
function, which redirects to the previous page, redirects the user to a random page because it is pre-loaded by the browser.
It will be necessary to be able to say to the backend not to record this pre-loading.
Hi,
I've included the umd version of quicklinks but I keep getting several console errors repeating the error:
Uncaught (in promise) Event {isTrusted: true, type: "error", target: link, currentTarget: null, eventPhase: 0, …}bubbles: falsecancelBubble: falsecancelable: falsecomposed: falsecurrentTarget: nulldefaultPrevented: falseeventPhase: 0isTrusted: truepath: (5) [link, head, html.js.no-focus-outline.sizes.customelements.history.pointerevents.postmessage.webgl.websockets.css…, document, Window]returnValue: truesrcElement: linktarget: linktimeStamp: 2088.500000001659type: "error"__proto__: Event
Promise.then (async)
r @ quicklink.umd.js:1
c @ quicklink.umd.js:1
(anonymous) @ quicklink.umd.js:1
(anonymous) @ quicklink.umd.js:1
Any advice with resolving these errors would be great. Thanks.
https://github.com/GoogleChromeLabs/quicklink/blob/master/src/prefetch.mjs
line 104.
if (conn = navigator.connection) {
// Don't prefetch if the user is on 2G. or if Save-Data is enabled..
if ((conn.effectiveType || '').includes('2g') || conn.saveData) return;
}
is that right?
Hello! 👋
Not flagging this to suggest it should work in anything below IE11, but the README currently says quicklink
supports IE9+ as long as you have an Intersection Observer polyfill. However Set
is not available until IE11. I think a user would need to have a Set polyfill in place to ensure it works that far back?
Apologies if I'm missing something! But wanted to flag just in case.
Does it make sense to prefetch links as the user is scrolling?
Here's a screencast of an example where I'm reading a JavaScript usecase and when I scroll towards the end, it would be nice for quicklink to prefetch those 2 related usecases
Screencast link: https://photos.app.goo.gl/mHgwbTmoKYXmXudEA
When using this locally it works great, but when in production, the prefetched links get blocked because of 'mixed content' and I get the 'This page is trying to load scripts from unauthenticated sources' alert.
This comes up in the console:
Mixed Content: The page at 'https://livi.com.ar/evaluacion?id=24' was loaded over HTTPS, but requested an insecure prefetch resource 'http://livi.com.ar/evaluacion?id=14'. This request has been blocked; the content must be served over HTTPS.
Any help?
I haven't experimented, but I think you could manipulate priority by using e.g. <link rel="preload" as="image | script | style | ..." href="theLinkToPreload">
?
Depending on the number of links on a page, or if new links are added programmatically after the initial call. Both the query selector in the timeout method https://github.com/GoogleChromeLabs/quicklink/blob/master/src/index.mjs#L70, and/or the entries loop in the observer callback https://github.com/GoogleChromeLabs/quicklink/blob/master/src/index.mjs#L23, could be problematic for subsequent calls.
I think it would be worth to unobserve
elements that are already prefetched.
Additionally, instead of requiring additional calls to quicklink({ urls: [..]})
, which I think it is still needed to override the intersection observer; a mutationobserver.mjs
could be enabled through an option, or to keep the lib size down, expose it in dist and allow its default export to be passed as an option for runtime.
Let me know what you think and I can tackle these. 👍
Thanks!
Hello,
I've tested quicklink using the test/
page with Chrome/Chromium which works very well, however, it doesn't work at all with Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0
(On Linux Mint 19.1 Tessa
), both the current latest 8c007ab and v1.0.0, and there is no error or warning message in the developer tool console. I haven't tested on other environments yet.
Not sure if anyone else has the same issue and what should I do to help locate that issue, let me know if I missed anything or how can I help please, thank you!
Would this work by default with react-native projects? Or any idea how to make it work in react-native?
Is it necessary to set the Cache-Control
Header to a specifc value to take advantage of prefetching?
On the demo Site https://keyword-2-ecd7b.firebaseapp.com/
I can see a Cache-Control
Header of max-age=3600
. Would quicklink
also work with a Cache-Control: no-cache
header?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.