GithubHelp home page GithubHelp logo

googlechromelabs / quicklink Goto Github PK

View Code? Open in Web Editor NEW
10.9K 96.0 399.0 12.23 MB

⚡️Faster subsequent page-loads by prefetching in-viewport links during idle time

Home Page: https://getquick.link

License: Apache License 2.0

JavaScript 92.10% SCSS 7.90%
performance web-performance prefetch prefetcher speed

quicklink's Issues

Normalize URLs before checking the `toPrefetch` set

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

const url = entry.target.href;
, you’d get the following normalized URL for each of those three:

https://www.google.com/

However, the same normalization is not applied when the user manually passes in URLs:

options.urls.forEach(prefetcher);

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:

options.urls.forEach(prefetcher);

-      options.urls.forEach(prefetcher);
+      options.urls.forEach(url => prefetcher(new URL(url).toString()));

Add option to ignore href with target="_blank"

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

Facilitate development of plugin in existing WordPress dev environment

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.

ignore configuration filter can be bypassed by links sharing survivors urls

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

Ignore elements?

Can you ignore specific elements? "Quicklink everything but [...]" case

Add demos using `quicklink`

These are already deployed with before/afters on WebPageTest. Just need to decide whether to include them in the README or wiki.

Does not work as a traditional JS resource – Uncaught ReferenceError: module is not defined

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.

Consider allowing quicklink to fail softly if IntersectionObserver isn't available.

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.

Quicklink is not actually IUU

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.

Does link prefetching work with target="_blank"?

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?

Ability to exclude some links from prefetching

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 😄?

shouldn't window.addEventListener (in readme) use passive and/or once ?

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 !)

IE11 doesn't seem to play ball with quicklink();

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 :)

Why not a chrome plugin?

I am wondering why there is no chrome plugin that would load this on any page? Am I overseeing something?

net::ERR_UNKNOWN_URL_SCHEME

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

how about fix it about cors?

"No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled."
QQ截图20190406150429

Still fetch ignored URL

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 ?

Usage with barba/turbolinks/etc

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

Facilitate async loading of quicklink.umd.js

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>

Option to ignore certain URLs by extension

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.

Unwanted behavior of the library

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.

Uncaught (in promise)

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.

Feature request: ability to set rough link fetching order

I would love the ability to set a rough "order" on the prefetching of links through something like:

quicklink({
  order: [
    (uri, elem) => {
      const importantSelector = '.primary a';
      if (elem.matches(importantSelector)) return 0; // Zero would indicate super important;
    }
  ]
});

image

Set does not work in <IE11

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.

Requests blocked because of mixed content

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?

Unobserve prefetched elements

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!

Not working on Firefox v65

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!

`prefetch` in combination of `Cache-Control`

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.