Skip to content

Commit a56fb4b

Browse files
committed
Modernize code and improve readability
1 parent 909accb commit a56fb4b

File tree

7 files changed

+99
-93
lines changed

7 files changed

+99
-93
lines changed

.size-limit.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
},
1717
{
1818
"path": "dist/quicklink.umd.js",
19-
"limit": "2.51 kB",
19+
"limit": "2.55 kB",
2020
"gzip": true
2121
}
2222
]

src/chunks.mjs

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ const toPrefetch = new Set();
3232
* @return {Boolean} If true, then it should be ignored
3333
*/
3434
function isIgnored(node, filter) {
35-
return Array.isArray(filter) ?
36-
filter.some(x => isIgnored(node, x)) :
37-
(filter.test || filter).call(filter, node.href, node);
35+
if (Array.isArray(filter)) {
36+
return filter.some(x => isIgnored(node, x));
37+
}
38+
39+
return (filter.test || filter).call(filter, node.href, node);
3840
}
3941

4042
/**
@@ -59,8 +61,8 @@ function isIgnored(node, filter) {
5961
export function listen(options = {}) {
6062
if (!window.IntersectionObserver) return;
6163

62-
const [toAdd, isDone] = throttle(options.throttle || 1 / 0);
63-
const limit = options.limit || 1 / 0;
64+
const [toAdd, isDone] = throttle(options.throttle || Number.Infinity);
65+
const limit = options.limit || Number.Infinity;
6466

6567
const allowed = options.origins || [location.hostname];
6668
const ignores = options.ignores || [];
@@ -79,36 +81,37 @@ export function listen(options = {}) {
7981
};
8082

8183
const observer = new IntersectionObserver(entries => {
82-
entries.forEach(entry => {
83-
if (entry.isIntersecting) {
84-
observer.unobserve(entry = entry.target);
85-
// Do not prefetch if will match/exceed limit
86-
if (toPrefetch.size < limit) {
87-
toAdd(() => {
88-
prefetchChunks ?
89-
prefetchChunks(entry, prefetchHandler) :
90-
prefetchHandler(entry.href);
91-
});
92-
}
84+
for (const {isIntersecting, target} of entries) {
85+
if (!isIntersecting) continue;
86+
87+
observer.unobserve(target);
88+
// Do not prefetch if will match/exceed limit
89+
if (toPrefetch.size < limit) {
90+
toAdd(() => {
91+
prefetchChunks ?
92+
prefetchChunks(target, prefetchHandler) :
93+
prefetchHandler(target.href);
94+
});
9395
}
94-
});
96+
}
9597
});
9698

9799
timeoutFn(() => {
98100
// Find all links & Connect them to IO if allowed
99-
(options.el || document).querySelectorAll('a').forEach(link => {
101+
const links = (options.el || document).querySelectorAll('a[href]');
102+
for (const link of links) {
100103
// If the anchor matches a permitted origin
101104
// ~> A `[]` or `true` means everything is allowed
102105
if (!allowed.length || allowed.includes(link.hostname)) {
103106
// If there are any filters, the link must not match any of them
104107
if (!isIgnored(link, ignores)) observer.observe(link);
105108
}
106-
});
109+
}
107110
}, {
108111
timeout: options.timeout || 2000,
109112
});
110113

111-
return function () {
114+
return () => {
112115
// wipe url list
113116
toPrefetch.clear();
114117
// detach IO entries
@@ -124,30 +127,25 @@ export function listen(options = {}) {
124127
*/
125128
export function prefetch(url, isPriority) {
126129
const {connection} = navigator;
130+
if (!connection) return Promise.resolve();
127131

128-
if (connection) {
129-
// Don't prefetch if using 2G or if Save-Data is enabled.
130-
if (connection.saveData) {
131-
return Promise.reject(new Error('Cannot prefetch, Save-Data is enabled'));
132-
}
132+
// Don't prefetch if using 2G or if Save-Data is enabled.
133+
if (connection.saveData) {
134+
return Promise.reject(new Error('Cannot prefetch, Save-Data is enabled'));
135+
}
133136

134-
if (/2g/.test(connection.effectiveType)) {
135-
return Promise.reject(new Error('Cannot prefetch, network conditions are poor'));
136-
}
137+
if (/2g/.test(connection.effectiveType)) {
138+
return Promise.reject(new Error('Cannot prefetch, network conditions are poor'));
137139
}
138140

139141
// Dev must supply own catch()
140-
return Promise.all(
141-
[].concat(url).map(str => {
142-
if (toPrefetch.has(str)) return [];
143-
144-
// Add it now, regardless of its success
145-
// ~> so that we don't repeat broken links
146-
toPrefetch.add(str);
147-
148-
return (isPriority ? viaFetch : supported)(
149-
new URL(str, location.href).toString(),
150-
);
151-
}),
152-
);
142+
return Promise.all([url].flat().map(str => {
143+
if (toPrefetch.has(str)) return [];
144+
145+
// Add it now, regardless of its success
146+
// ~> so that we don't repeat broken links
147+
toPrefetch.add(str);
148+
149+
return (isPriority ? viaFetch : supported)(new URL(str, location.href).toString());
150+
}));
153151
}

src/index.mjs

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,17 @@ function isIgnored(node, filter) {
4949
* @return {Boolean|Object} Error Object if the constrainsts are met or boolean otherwise
5050
*/
5151
function checkConnection(conn) {
52-
if (conn) {
53-
// Don't pre* if using 2G or if Save-Data is enabled.
54-
if (conn.saveData) {
55-
return new Error('Save-Data is enabled');
56-
}
52+
// If no connection object, assume it's okay to prefetch
53+
if (!conn) return true;
5754

58-
if (/2g/.test(conn.effectiveType)) {
59-
return new Error('network conditions are poor');
60-
}
55+
// Don't prefetch if Save-Data is enabled.
56+
if (conn.saveData) {
57+
return new Error('Save-Data is enabled');
58+
}
59+
60+
// Don't prefetch if using 2G connection.
61+
if (/2g/.test(conn.effectiveType)) {
62+
return new Error('network conditions are poor');
6163
}
6264

6365
return true;
@@ -120,7 +122,7 @@ export function listen(options = {}) {
120122
};
121123

122124
const observer = new IntersectionObserver(entries => {
123-
entries.forEach(entry => {
125+
for (let entry of entries) {
124126
// On enter
125127
if (entry.isIntersecting) {
126128
entry = entry.target;
@@ -140,7 +142,11 @@ export function listen(options = {}) {
140142
// either it's the prerender + prefetch mode or it's prerender *only* mode
141143
// Prerendering limit is following options.limit. UA may impose arbitraty numeric limit
142144
// The same URL is not already present as a speculation rule
143-
if ((shouldPrerenderAndPrefetch || shouldOnlyPrerender) && toPrerender.size < limit && !specRulesInViewport.has(entry.href)) {
145+
if (
146+
(shouldPrerenderAndPrefetch || shouldOnlyPrerender) &&
147+
toPrerender.size < limit &&
148+
!specRulesInViewport.has(entry.href)
149+
) {
144150
prerender(hrefFn ? hrefFn(entry) : entry.href, options.eagerness)
145151
.then(specMap => {
146152
for (const [key, value] of specMap) {
@@ -161,8 +167,13 @@ export function listen(options = {}) {
161167
// Do not prefetch if will match/exceed limit and user has not switched to shouldOnlyPrerender mode
162168
if (toPrefetch.size < limit && !shouldOnlyPrerender) {
163169
toAdd(() => {
164-
prefetch(hrefFn ? hrefFn(entry) : entry.href, options.priority,
165-
options.checkAccessControlAllowOrigin, options.checkAccessControlAllowCredentials, options.onlyOnMouseover)
170+
prefetch(
171+
hrefFn ? hrefFn(entry) : entry.href,
172+
options.priority,
173+
options.checkAccessControlAllowOrigin,
174+
options.checkAccessControlAllowCredentials,
175+
options.onlyOnMouseover,
176+
)
166177
.then(isDone)
167178
.catch(error => {
168179
isDone();
@@ -176,41 +187,37 @@ export function listen(options = {}) {
176187
entry = entry.target;
177188
const index = hrefsInViewport.indexOf(entry.href);
178189

179-
if (index > -1) {
190+
if (index !== -1) {
180191
hrefsInViewport.splice(index);
181192
}
182193

183194
if (specRulesInViewport.has(entry.href)) {
184195
specRulesInViewport.set(removeSpeculationRule(specRulesInViewport, entry.href));
185196
}
186197
}
187-
});
198+
}
188199
}, {
189200
threshold,
190201
});
191202

192203
timeoutFn(() => {
193204
// Find all links & Connect them to IO if allowed
194-
const elementsToListen = options.el &&
195-
options.el.length &&
196-
options.el.length > 0 &&
197-
options.el[0].nodeName === 'A' ?
198-
options.el :
199-
(options.el || document).querySelectorAll('a');
200-
201-
elementsToListen.forEach(link => {
205+
const isAnchorElement = options.el && options.el.length > 0 && options.el[0].nodeName === 'A';
206+
const elementsToListen = isAnchorElement ? options.el : (options.el || document).querySelectorAll('a');
207+
208+
for (const link of elementsToListen) {
202209
// If the anchor matches a permitted origin
203210
// ~> A `[]` or `true` means everything is allowed
204211
if (!allowed.length || allowed.includes(link.hostname)) {
205212
// If there are any filters, the link must not match any of them
206213
if (!isIgnored(link, ignores)) observer.observe(link);
207214
}
208-
});
215+
}
209216
}, {
210217
timeout: options.timeout || 2000,
211218
});
212219

213-
return function () {
220+
return () => {
214221
// wipe url list
215222
toPrefetch.clear();
216223
// detach IO entries
@@ -239,18 +246,22 @@ export function prefetch(urls, isPriority, checkAccessControlAllowOrigin, checkA
239246
}
240247

241248
// Dev must supply own catch()
242-
return Promise.all(
243-
[].concat(urls).map(str => {
244-
if (toPrefetch.has(str)) return [];
245-
246-
// Add it now, regardless of its success
247-
// ~> so that we don't repeat broken links
248-
toPrefetch.add(str);
249-
250-
return prefetchOnHover((isPriority ? viaFetch : supported), new URL(str, location.href).toString(), onlyOnMouseover,
251-
checkAccessControlAllowOrigin, checkAccessControlAllowCredentials, isPriority);
252-
}),
253-
);
249+
return Promise.all([urls].flat().map(str => {
250+
if (toPrefetch.has(str)) return [];
251+
252+
// Add it now, regardless of its success
253+
// ~> so that we don't repeat broken links
254+
toPrefetch.add(str);
255+
256+
return prefetchOnHover(
257+
isPriority ? viaFetch : supported,
258+
new URL(str, location.href).toString(),
259+
onlyOnMouseover,
260+
checkAccessControlAllowOrigin,
261+
checkAccessControlAllowCredentials,
262+
isPriority,
263+
);
264+
}));
254265
}
255266

256267
/**
@@ -260,7 +271,7 @@ export function prefetch(urls, isPriority, checkAccessControlAllowOrigin, checkA
260271
* @return {Object} a Promise
261272
*/
262273
export function prerender(urls, eagerness = 'immediate') {
263-
urls = [].concat(urls);
274+
urls = [urls].flat();
264275

265276
const chkConn = checkConnection(navigator.connection);
266277
if (chkConn instanceof Error) {

src/prefetch.mjs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ function viaDOM(url, hasCrossorigin) {
4646
link.onload = resolve;
4747
link.onerror = reject;
4848

49-
document.head.appendChild(link);
49+
document.head.append(link);
5050
});
5151
}
5252

@@ -97,7 +97,7 @@ export function viaFetch(url, hasModeCors, hasCredentials, isPriority) {
9797
const options = {headers: {accept: '*/*'}};
9898
if (!hasModeCors) options.mode = 'no-cors';
9999
if (hasCredentials) options.credentials = 'include';
100-
isPriority ? options.priority = 'high' : options.priority = 'low';
100+
options.priority = isPriority ? 'high' : 'low';
101101
return window.fetch ? fetch(url, options) : viaXHR(url, hasCredentials);
102102
}
103103

@@ -116,7 +116,7 @@ export function prefetchOnHover(callback, url, onlyOnMouseover, ...args) {
116116
const timerMap = new Map();
117117

118118
for (const el of elements) {
119-
const mouseenterListener = _ => {
119+
const mouseenterListener = () => {
120120
const timer = setTimeout(() => {
121121
el.removeEventListener('mouseenter', mouseenterListener);
122122
el.removeEventListener('mouseleave', mouseleaveListener);
@@ -125,7 +125,7 @@ export function prefetchOnHover(callback, url, onlyOnMouseover, ...args) {
125125
timerMap.set(el, timer);
126126
};
127127

128-
const mouseleaveListener = _ => {
128+
const mouseleaveListener = () => {
129129
const timer = timerMap.get(el);
130130
if (timer) {
131131
clearTimeout(timer);

src/prerender.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export function addSpeculationRules(urlsToPrerender, eagerness) {
3838
}],
3939
});
4040

41-
document.head.appendChild(specScript);
41+
document.head.append(specScript);
4242
specMap.set(url, specScript);
4343
}
4444
} catch (error) {

src/react-chunks.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const useIntersect = ({root = null, rootMargin, threshold = 0} = {}) => {
2525

2626
useEffect(() => {
2727
if (observer.current) observer.current.disconnect();
28+
2829
observer.current = new window.IntersectionObserver(
2930
([entry]) => updateEntry(entry),
3031
{
@@ -43,14 +44,12 @@ const useIntersect = ({root = null, rootMargin, threshold = 0} = {}) => {
4344
return [setNode, entry];
4445
};
4546

46-
const __defaultAccessor = mix => {
47-
return (mix && mix.href) || mix || '';
48-
};
47+
const __defaultAccessor = mix => (mix && mix.href) || mix || '';
4948

5049
const prefetchChunks = (entry, prefetchHandler, accessor = __defaultAccessor) => {
5150
const {files} = rmanifest(window.__rmanifest, entry.pathname);
5251
const chunkURLs = files.map(accessor).filter(Boolean);
53-
if (chunkURLs.length) {
52+
if (chunkURLs.length > 0) {
5453
prefetchHandler(chunkURLs);
5554
} else {
5655
// also prefetch regular links in-viewport

src/request-idle-callback.mjs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,14 @@
1616

1717
// RIC and shim for browsers setTimeout() without it
1818
const requestIdleCallback = window.requestIdleCallback ||
19-
function (cb) {
19+
(cb => {
2020
const start = Date.now();
2121
return setTimeout(() => {
2222
cb({
2323
didTimeout: false,
24-
timeRemaining() {
25-
return Math.max(0, 50 - (Date.now() - start));
26-
},
24+
timeRemaining: () => Math.max(0, 50 - (Date.now() - start)),
2725
});
2826
}, 1);
29-
};
27+
});
3028

3129
export default requestIdleCallback;

0 commit comments

Comments
 (0)