New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

quicklink

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

quicklink - npm Package Compare versions

Comparing version 0.1.2 to 1.0.0

test/test-allow-origin-all.html

2

dist/quicklink.js

@@ -1,1 +0,1 @@

var e={};function t(e){return new Promise(function(t,n){var r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=function(){200===r.status?t():n()},r.send()})}var n=function(e){if("undefined"==typeof document)return!1;try{var t=document.createElement("link");if(t.relList&&"function"==typeof t.relList.supports)return t.relList.supports(e)}catch(e){return!1}}("prefetch")?function(e){return new Promise(function(t,n){var r=document.createElement("link");r.rel="prefetch",r.href=e,r.onload=t,r.onerror=n,(document.head||document.querySelector("script").parentNode).appendChild(r)})}:t;function r(r,i){if(!e[r]){if("connection"in navigator){if((navigator.connection.effectiveType||"").includes("2g"))return;if(navigator.connection.saveData)return}return(i?function(e){return null==self.fetch?t(e):fetch(e,{credentials:"include"})}:n)(r).then(function(){e[r]=!0})}}var i=i||function(e){var t=Date.now();return setTimeout(function(){e({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-t))}})},1)},o=new Set,u=new IntersectionObserver(function(e){e.forEach(function(e){if(e.isIntersecting){var t=e.target.href;o.has(t)&&c(t)}})});function c(e){o.delete(e),r(e,u.priority)}module.exports=function(e){e=Object.assign({timeout:2e3,priority:!1,timeoutFn:i,el:document},e),u.priority=e.priority,e.timeoutFn(function(){e.urls?e.urls.forEach(c):Array.from(e.el.querySelectorAll("a"),function(e){u.observe(e),o.add(e.href)})},{timeout:e.timeout})};
var e={};function t(e){return new Promise(function(t,n){var r=new XMLHttpRequest;r.open("GET",e,r.withCredentials=!0),r.onload=function(){200===r.status?t():n()},r.send()})}var n,r,o=(n="prefetch",((r=document.createElement("link")).relList||{}).supports&&r.relList.supports(n)?function(e){return new Promise(function(t,n){var r=document.createElement("link");r.rel="prefetch",r.href=e,r.onload=t,r.onerror=n,document.head.appendChild(r)})}:t);function i(n,r,i){if(!(e[n]||(i=navigator.connection)&&((i.effectiveType||"").includes("2g")||i.saveData)))return(r?function(e){return null==self.fetch?t(e):fetch(e,{credentials:"include"})}:o)(n).then(function(){e[n]=!0})}var u=u||function(e){var t=Date.now();return setTimeout(function(){e({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-t))}})},1)},c=new Set,a=new IntersectionObserver(function(e){e.forEach(function(e){if(e.isIntersecting){var t=e.target.href;c.has(t)&&s(t)}})});function s(e){c.delete(e),i(new URL(e,location.href).toString(),a.priority)}module.exports=function(e){e=Object.assign({timeout:2e3,priority:!1,timeoutFn:u,el:document},e),a.priority=e.priority;var t=e.origins||[location.hostname],n=e.ignores||[];e.timeoutFn(function(){e.urls?e.urls.forEach(s):Array.from(e.el.querySelectorAll("a"),function(e){a.observe(e),t.length&&!t.includes(e.hostname)||function e(t,n){return Array.isArray(n)?n.some(function(n){return e(t,n)}):(n.test||n).call(n,t.href,t)}(e,n)||c.add(e.href)})},{timeout:e.timeout})};

@@ -1,1 +0,1 @@

!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):e.quicklink=n()}(this,function(){var e={};function n(e){return new Promise(function(n,t){var r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=function(){200===r.status?n():t()},r.send()})}var t=function(e){if("undefined"==typeof document)return!1;try{var n=document.createElement("link");if(n.relList&&"function"==typeof n.relList.supports)return n.relList.supports(e)}catch(e){return!1}}("prefetch")?function(e){return new Promise(function(n,t){var r=document.createElement("link");r.rel="prefetch",r.href=e,r.onload=n,r.onerror=t,(document.head||document.querySelector("script").parentNode).appendChild(r)})}:n;function r(r,i){if(!e[r]){if("connection"in navigator){if((navigator.connection.effectiveType||"").includes("2g"))return;if(navigator.connection.saveData)return}return(i?function(e){return null==self.fetch?n(e):fetch(e,{credentials:"include"})}:t)(r).then(function(){e[r]=!0})}}var i=i||function(e){var n=Date.now();return setTimeout(function(){e({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-n))}})},1)},o=new Set,u=new IntersectionObserver(function(e){e.forEach(function(e){if(e.isIntersecting){var n=e.target.href;o.has(n)&&c(n)}})});function c(e){o.delete(e),r(e,u.priority)}return function(e){e=Object.assign({timeout:2e3,priority:!1,timeoutFn:i,el:document},e),u.priority=e.priority,e.timeoutFn(function(){e.urls?e.urls.forEach(c):Array.from(e.el.querySelectorAll("a"),function(e){u.observe(e),o.add(e.href)})},{timeout:e.timeout})}});
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):e.quicklink=n()}(this,function(){var e={};function n(e){return new Promise(function(n,t){var r=new XMLHttpRequest;r.open("GET",e,r.withCredentials=!0),r.onload=function(){200===r.status?n():t()},r.send()})}var t,r,i=(t="prefetch",((r=document.createElement("link")).relList||{}).supports&&r.relList.supports(t)?function(e){return new Promise(function(n,t){var r=document.createElement("link");r.rel="prefetch",r.href=e,r.onload=n,r.onerror=t,document.head.appendChild(r)})}:n);function o(t,r,o){if(!(e[t]||(o=navigator.connection)&&((o.effectiveType||"").includes("2g")||o.saveData)))return(r?function(e){return null==self.fetch?n(e):fetch(e,{credentials:"include"})}:i)(t).then(function(){e[t]=!0})}var u=u||function(e){var n=Date.now();return setTimeout(function(){e({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-n))}})},1)},c=new Set,f=new IntersectionObserver(function(e){e.forEach(function(e){if(e.isIntersecting){var n=e.target.href;c.has(n)&&a(n)}})});function a(e){c.delete(e),o(new URL(e,location.href).toString(),f.priority)}return function(e){e=Object.assign({timeout:2e3,priority:!1,timeoutFn:u,el:document},e),f.priority=e.priority;var n=e.origins||[location.hostname],t=e.ignores||[];e.timeoutFn(function(){e.urls?e.urls.forEach(a):Array.from(e.el.querySelectorAll("a"),function(e){f.observe(e),n.length&&!n.includes(e.hostname)||function e(n,t){return Array.isArray(t)?t.some(function(t){return e(n,t)}):(t.test||t).call(t,n.href,n)}(e,t)||c.add(e.href)})},{timeout:e.timeout})}});
{
"name": "quicklink",
"version": "0.1.2",
"version": "1.0.0",
"description": "Faster subsequent page-loads by prefetching in-viewport links during idle time",

@@ -12,2 +12,3 @@ "main": "dist/quicklink.js",

"umd:main": "dist/quicklink.umd.js",
"unpkg": "dist/quicklink.umd.js",
"scripts": {

@@ -14,0 +15,0 @@ "lint": "eslint src/*.mjs test/*.js demos/*.js",

@@ -38,3 +38,3 @@ <p align="center">

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

@@ -84,2 +84,4 @@ Quickstart:

* `priority`: Boolean specifying preferred priority for fetches. Defaults to `false`. `true` will attempt to use the `fetch()` API where supported (rather than rel=prefetch)
* `origins`: Static array of URL hostname strings that are allowed to be prefetched. Defaults to the same domain origin, which prevents _any_ cross-origin requests.
* `ignores`: A RegExp, Function, or Array that further determines if a URL should be prefetched. These execute _after_ origin matching.

@@ -95,3 +97,3 @@ TODO:

* Includes a very small fallback for [requestIdleCallback](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback)
* Requires `IntersectionObserver` to be supported (see [CanIUse](https://caniuse.com/#feat=intersectionobserver)). We recommend conditionally polyfillng this feature with a service like Polyfill.io:
* Requires `IntersectionObserver` to be supported (see [CanIUse](https://caniuse.com/#feat=intersectionobserver)). We recommend conditionally polyfilling this feature with a service like Polyfill.io:

@@ -145,2 +147,57 @@ ```html

**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!
```js
quicklink({
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](https://chromium.googlesource.com/chromium/src/+/master/services/network/cross_origin_read_blocking_explainer.md) and [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) issues!
```js
quicklink({
origins: true,
// or
origins: []
});
```
**Custom Ignore Patterns**
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
// 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({
ignores: [
/\/api\/?/,
uri => uri.includes('.zip'),
(uri, elem) => elem.hasAttribute('noprefetch')
]
});
```
## Browser support

@@ -153,4 +210,7 @@

Certain features have layered support. If opting for `{priority: true}` and `fetch()` isn't available, XHR will be used instead.
Certain features have layered support:
* The [Network Information API](https://wicg.github.io/netinfo/), which is used to check if the user has a slow effective connection type (via `navigator.connection.effectiveType`) is only available in [Chrome 61+ and Opera 57+](https://caniuse.com/#feat=netinfo)
* If opting for `{priority: true}` and the [Fetch API](https://fetch.spec.whatwg.org/) isn't available, XHR will be used instead.
## Using the prefetcher directly

@@ -175,3 +235,3 @@

For demo purposes, we deployed a version of the [Google Blog](https://blog.google) 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
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.

@@ -183,3 +243,3 @@

* Using [Gatsby](https://gatsbyjs.org)? You already get most of this for free baked in. It uses `Intersection Observer` to prefetch all of the links that are in view and provided heavy inspiration for this project.
* Using [Gatsby](https://gatsbyjs.org)? You already get most of this for free baked in. It uses `Intersection Observer` to prefetch all of the links that are in view and provided heavy inspiration for this project.
* Want a more data-driven approach? See [Guess.js](https://guess-js.github.io). It uses analytics and machine-learning to prefetch resources based on how users navigate your site. It also has plugins for [Webpack](https://www.npmjs.com/package/guess-webpack) and [Gatsby](https://www.gatsbyjs.org/docs/optimize-prefetching-with-guessjs/).

@@ -186,0 +246,0 @@

@@ -82,2 +82,89 @@ describe('quicklink tests', function () {

});
it('should only prefetch links if allowed in origins list', async function () {
const responseURLs = [];
page.on('response', resp => {
responseURLs.push(resp.url());
});
await page.goto(`${server}/test-allow-origin.html`);
await page.waitFor(1000);
expect(responseURLs).to.be.an('array');
// => origins: ['github.githubassets.com']
expect(responseURLs).to.not.include(`${server}/2.html`);
expect(responseURLs).to.include('https://example.com/1.html');
expect(responseURLs).to.include('https://github.githubassets.com/images/spinners/octocat-spinner-32.gif');
});
it('should prefetch all links when allowing all origins', async function () {
const responseURLs = [];
page.on('response', resp => {
responseURLs.push(resp.url());
});
await page.goto(`${server}/test-allow-origin-all.html`);
await page.waitFor(1000);
expect(responseURLs).to.be.an('array');
// => origins: true
expect(responseURLs).to.include(`${server}/2.html`);
expect(responseURLs).to.include('https://foobar.com/3.html');
expect(responseURLs).to.include('https://example.com/1.html');
expect(responseURLs).to.include('https://github.githubassets.com/images/spinners/octocat-spinner-32.gif');
});
it('should only prefetch links of same origin (default)', async function () {
const responseURLs = [];
page.on('response', resp => {
responseURLs.push(resp.url());
});
await page.goto(`${server}/test-same-origin.html`);
await page.waitFor(1000);
expect(responseURLs).to.be.an('array');
// => origins: [location.hostname] (default)
expect(responseURLs).to.include(`${server}/2.html`);
expect(responseURLs).to.not.include('https://example.com/1.html');
expect(responseURLs).to.not.include('https://github.githubassets.com/images/spinners/octocat-spinner-32.gif');
});
it('should only prefetch links after ignore patterns allowed it', async function () {
const responseURLs = [];
page.on('response', resp => {
responseURLs.push(resp.url());
});
await page.goto(`${server}/test-ignore-basic.html`);
await page.waitFor(1000);
expect(responseURLs).to.be.an('array');
// => origins: [location.hostname] (default)
// => ignores: /2.html/
// via ignores
expect(responseURLs).to.not.include(`${server}/2.html`);
// via same origin
expect(responseURLs).to.not.include('https://example.com/1.html');
// via same origin
expect(responseURLs).to.not.include('https://github.githubassets.com/images/spinners/octocat-spinner-32.gif');
});
it('should only prefetch links after ignore patterns allowed it (multiple)', async function () {
const responseURLs = [];
page.on('response', resp => {
responseURLs.push(resp.url());
});
await page.goto(`${server}/test-ignore-multiple.html`);
await page.waitFor(1000);
expect(responseURLs).to.be.an('array');
// => origins: true (all)
// => ignores: [...]
expect(responseURLs).to.include(`${server}/2.html`);
// /example/
expect(responseURLs).to.not.include('https://example.com/1.html');
// (uri) => uri.includes('foobar')
expect(responseURLs).to.not.include('https://foobar.com/3.html');
// (uri, elem) => elem.textContent.includes('Spinner')
expect(responseURLs).to.not.include('https://github.githubassets.com/images/spinners/octocat-spinner-32.gif');
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc