quicklink README

The project's README from github.com/GoogleChromeLabs/quicklink. As one markdown file: README.md.


npm gzip size ci

quicklink

Faster subsequent page-loads by prefetching or prerendering in-viewport links during idle time

How it works

Quicklink attempts to make navigations to subsequent pages load faster. It:

Why

This project aims to be a drop-in solution for sites to prefetch or prerender links based on what is in the user's viewport. It also aims to be small (< 2KB minified/gzipped).

Multi page apps

Installation

For use with Node.js and npm:

npm install quicklink

You can also grab quicklink from unpkg.com/quicklink.

Usage

Once initialized, quicklink will automatically prefetch URLs for links that are in-viewport during idle time.

Quickstart:

<!-- Include quicklink from dist -->
<script src="dist/quicklink.umd.js"></script>
<!-- Initialize (you can do this whenever you want) -->
<script>
  quicklink.listen();
</script>

For example, you can initialize after the load event fires:

<script>
  window.addEventListener('load', () => {
    quicklink.listen();
  });
</script>

ES Module import:

import {listen, prefetch} from 'quicklink';

Modern ES Module (quicklink.modern.mjs) — a smaller build for browsers with native ES module support (no legacy transforms). Prefer this when you only need to support modern browsers:

import {listen, prefetch} from 'quicklink/dist/quicklink.modern.mjs';

Single page apps (React)

Installation

First, install the packages with Node.js and npm:

npm install quicklink webpack-route-manifest --save-dev

Then, configure Webpack route manifest into your project, as explained in the webpack-route-manifest docs. This will generate a map of routes and chunks called rmanifest.json. It can be obtained at:

Usage

Import quicklink React HOC where want to add prefetching functionality. Wrap your routes with the withQuicklink() HOC.

Example:

import {withQuicklink} from 'quicklink/dist/react/hoc.js';

const options = {
  origins: [],
};

<Suspense fallback={<div>Loading...</div>}>
  <Route path='/' exact component={withQuicklink(Home, options)} />
  <Route path='/blog' exact component={withQuicklink(Blog, options)} />
  <Route path='/blog/:title' component={withQuicklink(Article, options)} />
  <Route path='/about' exact component={withQuicklink(About, options)} />
</Suspense>;

API

quicklink.listen(options)

Returns: Function

A "reset" function is returned, which will empty the active IntersectionObserver and the cache of URLs that have already been prefetched or prerendered. This can be used between page navigations and/or when significant DOM changes have occurred.

options.prerender

Whether to switch from the default prefetching mode to the prerendering mode for the links inside the viewport.

Note: The prerendering mode (when this option is set to true) will fallback to the prefetching mode if the browser does not support prerender. Once the element exits the viewport, the speculationrules script is removed from the DOM. This approach makes it possible to exceed the limit of 10 prerenders imposed for the 'immediate' and 'eager' settings for eagerness.

options.eagerness

Determines the mode to be used for prerendering specified within the speculation rules.

options.prerenderAndPrefetch

Whether to activate both the prefetching and prerendering mode at the same time.

options.delay

The amount of time each link needs to stay inside the viewport before being prefetched, in milliseconds.

options.el

The DOM element to observe for in-viewport links to prefetch or the NodeList of Anchor Elements.

options.limit

The total requests that can be prefetched or prerendered while observing the options.el container.

options.threshold

The area percentage of each link that must have entered the viewport to be fetched, in its decimal form (e.g. 0.25 = 25%).

options.throttle

The concurrency limit for simultaneous requests while observing the options.el container.

options.timeout

The requestIdleCallback timeout, in milliseconds.

Note: The browser must be idle for the configured duration before prefetching.

options.timeoutFn

A function used for specifying a timeout delay.

This can be swapped out for a custom function like networkIdleCallback (see demos).

By default, this uses requestIdleCallback or the embedded polyfill.

options.priority

Whether or not the URLs within the options.el container should be treated as high priority.

When true, quicklink will attempt to use the fetch() API if supported (rather than link[rel=prefetch]).

options.origins

A static array of URL hostnames that are allowed to be prefetched.

Defaults to the same domain origin, which prevents any cross-origin requests.

Important: An empty array ([]) allows all origins to be prefetched.

options.ignores

Determine if a URL should be prefetched.

When a RegExp tests positive, a Function returns true, or an Array contains the string, then the URL is not prefetched.

Note: An Array may contain String, RegExp, or Function values.

Important: This logic is executed after origin matching!

options.onError

An optional error handler that will receive any errors from prefetched requests.

By default, these errors are silently ignored.

options.hrefFn

An optional function to generate the URL to prefetch. It receives an Element as the argument.

quicklink.prefetch(urls, isPriority)

Returns: Promise

The urls provided are always passed through Promise.all, which means the result will always resolve to an Array.

Important: You much catch you own request error(s).

urls

One or many URLs to be prefetched.

Note: Each url value is resolved from the current location.

isPriority

Whether or not the URL(s) should be treated as "high priority" targets.

By default, calls to prefetch() are low priority.

Note: This behaves identically to listen()'s priority option.

quicklink.prerender(urls, eagerness)

Returns: Promise

Important: You much catch you own request error(s).

urls

One or many URLs to be prerendered.

Note: Speculative Rules API supports same-site cross origin Prerendering with opt-in header.

eagerness

Determines the mode to be used for prerendering specified within the speculation rules.

Polyfills

quicklink:

Recipes

Set a custom timeout for prefetching resources

Defaults to 2 seconds (via requestIdleCallback). Here we override it to 4 seconds:

quicklink.listen({
  timeout: 4000,
});

Defaults to document otherwise.

quicklink.listen({
  el: document.querySelectorAll('a.linksToPrefetch'),
});

Defaults to document otherwise.

quicklink.listen({
  el: document.getElementById('carousel'),
});

Programmatically prefetch() URLs

If you would prefer to provide a static list of URLs to be prefetched, instead of detecting those in-viewport, customizing URLs is supported.

// Single URL
quicklink.prefetch('2.html');

// Multiple URLs
quicklink.prefetch(['2.html', '3.html', '4.js']);

// Multiple URLs, with high priority
// Note: Can also be use with single URL!
quicklink.prefetch(['2.html', '3.html', '4.js'], true);

Programmatically prerender() URLs

If you would prefer to provide a static list of URLs to be prerendered, instead of detecting those in-viewport, customizing URLs is supported.

// Single URL
quicklink.prerender('2.html');

// Multiple URLs
quicklink.prerender(['2.html', '3.html', '4.js']);

Set the request priority for prefetches while scrolling

Defaults to low-priority (rel=prefetch or XHR). For high-priority (priority: true), attempts to use fetch() or falls back to XHR.

Note: This runs prefetch(..., true) with URLs found within the options.el container.

quicklink.listen({priority: true});

Specify a custom list of allowed origins

Provide a list of hostnames that should be prefetch-able. Only the same origin is allowed by default.

Important: You must also include your own hostname!

quicklink.listen({
  origins: [
    // add mine
    'my-website.com',
    'api.my-website.com',
    // add third-parties
    'other-website.com',
    'example.com',
    // ...
  ],
});

Allow all origins

Enables all cross-origin requests to be made.

Note: You may run into CORB and CORS issues!

quicklink.listen({
  origins: true,
  // or
  origins: [],
});

Custom Ignore Patterns

By default, quicklink skips anchors that have a download attribute, since those often point at large binary payloads.

These filters run after the origins matching has run. Ignores can be useful for avoiding large file downloads or for responding to DOM attributes dynamically.

// Same-origin restraint is enabled by default.
//
// This example will ignore all requests to:
//  - all "/api/*" pathnames
//  - all ".zip" extensions
//  - all <a> tags with "noprefetch" attribute
//
quicklink.listen({
  ignores: [
    /\/api\/?/,
    uri => uri.includes('.zip'),
    (uri, elem) => elem.hasAttribute('noprefetch'),
  ],
});

You may also wish to ignore prefetches to URLs which contain a URL fragment (e.g. index.html#top). This can be useful if you (1) are using anchors to headings in a page or (2) have URL fragments setup for a single-page application, and which to avoid firing prefetches for similar URLs.

Using ignores this can be achieved as follows:

quicklink.listen({
  ignores: [
    uri => uri.includes('#'),
    // or RegExp: /#(.+)/
    // or element matching: (uri, elem) => !!elem.hash
  ],
});

Custom URL to prefetch via hrefFn callback

The hrefFn method allows to build the URL to prefetch (e.g. API endpoint) on the fly instead of the prefetching the href attribute URL.

quicklink.listen({
  hrefFn(element) {
    return element.href.replace('html', 'json');
  },
});

Browser Support

The prefetching provided by quicklink can be viewed as a progressive enhancement. Cross-browser support is as follows:

Certain features have layered support:

Using the prefetcher directly

A prefetch method can be individually imported for use in other projects.

This method includes the logic to respect Data Saver and 2G connections. It also issues requests thru fetch(), XHRs, or link[rel=prefetch] depending on (a) the isPriority value and (b) the current browser's support.

After installing quicklink as a dependency, you can use it as follows:

<script type="module">
  import {prefetch} from 'quicklink';
  prefetch(['1.html', '2.html']).catch(error => {
    // Handle own errors
  });
</script>

Demo

Live demos

The source for these demos lives under site/src/demos/.

Repo examples

Research

Here's a WebPageTest run for our demo improving page-load performance by up to 4 seconds via quicklink's prefetching. A video comparison of the before/after prefetching is on YouTube.

For demo purposes, we deployed a version of the Google Blog on Firebase hosting. We then deployed another version of it, adding quicklink to the homepage and benchmarked navigating from the homepage to an article that was automatically prefetched. The prefetched version loaded faster.

Please note: this is by no means an exhaustive benchmark of the pros and cons of in-viewport link prefetching. Just a demo of the potential improvements the approach can offer. Your own mileage may heavily vary.

Additional notes

Session Stitching

Cross-origin prefetching (e.g a.com/foo.html prefetches b.com/bar.html) has a number of limitations. One such limitation is with session-stitching. b.com may expect a.com's navigation requests to include session information (e.g a temporary ID - e.g b.com/bar.html?hash=<>&timestamp=<>), where this information is used to customize the experience or log information to analytics. If session-stitching requires a timestamp in the URL, what is prefetched and stored in the HTTP cache may not be the same as the one the user ultimately navigates to. This introduces a challenge as it can result in double prefetches.

To workaround this problem, you can consider passing along session information via the ping attribute (separately) so the origin can stitch a session together asynchronously.

Sites that rely on ads as a source of monetization should not prefetch ad-links, to avoid unintentionally counting clicks against those ad placements, which can lead to inflated Ad CTR (click-through-rate).

Ads appear on sites mostly in two ways:

License

Licensed under the Apache-2.0 license.

quicklink (GoogleChromeLabs/quicklink)

Searching Database…

11.3K ·GitHub
这是什么?Quicklink 是一个小型 JavaScript 库,它会在浏览器空闲时,预取或预渲染当前位于视口中的链接,从而加快之后的页面加载速度。
它是独立应用,还是我可以直接放进网站里使用的库?它是一个即插即用的 JavaScript 库或模块,您可以将其导入自己的网站或应用中;它不是托管服务,也不是构建工具。
我该如何把它添加到网站中?将其作为依赖项安装,然后调用 quicklink.listen()(或导入独立的 prefetch() 函数),开始监视视口中的链接;此外还有 WordPress 插件版本。
它需要任何构建工具或 polyfill 才能运行吗?它需要 IntersectionObserver 支持(旧版浏览器可通过 polyfill 补充),并内置了一个小型的 requestIdleCallback 回退方案;对于 IE9/10 等非常旧的浏览器,还需要 Set() 和 Array.from() 的 polyfill。
它会预取我不想要的链接吗,比如广告?默认情况下,它只预取同源链接,并会跳过带有 download 属性的锚点;但对于未在 iframe 中渲染的同源广告,需要通过 ignores 选项手动排除,以避免虚增广告点击率。
哪些浏览器真正能从中受益?它在 Chrome、Safari 12.1+、Firefox、Edge、Opera、Android Browser 和 Samsung Internet 上无需 polyfill 即可原生运行;在其他浏览器中会平稳降级(视为渐进增强)。
它会照顾网速慢或按流量计费的用户吗?会的。它会检查 navigator.connection.effectiveType 以及省流量(Data Saver)设置,对于网速较慢或开启了 Data Saver 的用户,会跳过预取。
预取模式和预渲染模式有什么区别?预取只是通过 link[rel=prefetch] 或 fetch/XHR 把资源下载到缓存中,而预渲染则使用 Speculation Rules API 在导航前真正提前渲染页面;如果浏览器不支持该 API,则回退为预取。
我能控制一次预取多少个链接吗?可以。像 limit、throttle 和 threshold 这样的选项,可以让您限制请求总数、限制并发请求数,并设置链接需要有多大比例可见后才进行预取。
除了整页导航,我还能把 quicklink 用于其他场景吗?可以。您可以单独导入 prefetch() 函数来预取任意资源,例如 API 调用;也可以使用 hrefFn 计算自定义 URL,代替锚点的 href。
为什么要开发 quicklink,而不直接使用 Gatsby 内置的预取功能?Quicklink 旨在成为一个小巧、与框架无关、即插即用的方案,让任何网站(而不仅仅是 Gatsby 应用)都能实现视口内链接预取。
What are similar projects?lazysizes, marked, core-js, critical, cdnjs, rspack, Sortable, codemirror5
Size
14.8 MB
Stars
11.3K
Age
7y
Commits · 90 Days