Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,8 @@ quicklink.listen({

### Custom Ignore Patterns

By default, quicklink skips anchors that have a [`download`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/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.

```js
Expand Down
5 changes: 3 additions & 2 deletions src/chunks.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@ export function listen(options = {}) {
});

timeoutFn(() => {
// Find all links & Connect them to IO if allowed
const links = (options.el || document).querySelectorAll('a[href]');
// Find all links & connect them to IO if allowed.
// Skip anchors with the `download` attribute (large payloads).
const links = (options.el || document).querySelectorAll('a[href]:not([download])');
for (const link of links) {
// If the anchor matches a permitted origin
// ~> A `[]` or `true` means everything is allowed
Expand Down
8 changes: 6 additions & 2 deletions src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,15 @@ export function listen(options = {}) {
});

timeoutFn(() => {
// Find all links & Connect them to IO if allowed
// Find all links & connect them to IO if allowed.
// Skip anchors with the `download` attribute - those often point at large
// binary payloads that are wasteful to prefetch.
const isAnchorElement = options.el && options.el.length > 0 && options.el[0].nodeName === 'A';
const elementsToListen = isAnchorElement ? options.el : (options.el || document).querySelectorAll('a');
const elementsToListen = isAnchorElement ? options.el : (options.el || document).querySelectorAll('a:not([download])');

for (const link of elementsToListen) {
// NodeList of anchors may still include download links
if (link.hasAttribute('download')) continue;
// If the anchor matches a permitted origin
// ~> A `[]` or `true` means everything is allowed
if (!allowed.length || allowed.includes(link.hostname)) {
Expand Down
22 changes: 22 additions & 0 deletions test/fixtures/test-ignore-download.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="utf-8">
<title>Prefetch: Ignore download attribute</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="main.css">
</head>

<body>
<a href="1.html">Link 1</a>
<a href="2.html" download>Download Link 2</a>
<a href="3.html" download="report.pdf">Download Link 3</a>
<a href="4.html" style="position:absolute;margin-top:900px;">Link 4</a>
<script src="../../dist/quicklink.umd.js"></script>
<script>
quicklink.listen();
</script>
</body>

</html>
18 changes: 18 additions & 0 deletions test/quicklink.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,24 @@ mainSuite('should only prefetch links after ignore patterns allowed it', async c
assert.not.ok(responseURLs.includes('https://github.githubassets.com/images/spinners/octocat-spinner-32.gif'));
});

mainSuite('should not prefetch links with the download attribute', async context => {
const responseURLs = [];
context.page.on('response', resp => {
responseURLs.push(resp.url());
});
await context.page.goto(`${server}/test-ignore-download.html`);
await sleep();
assert.instance(responseURLs, Array);

assert.ok(responseURLs.includes(`${server}/1.html`));
// boolean download attribute
assert.not.ok(responseURLs.includes(`${server}/2.html`));
// download="filename" attribute
assert.not.ok(responseURLs.includes(`${server}/3.html`));
// out of viewport
assert.not.ok(responseURLs.includes(`${server}/4.html`));
});

mainSuite('should only prefetch links after ignore patterns allowed it (multiple)', async context => {
const responseURLs = [];
context.page.on('response', resp => {
Expand Down