Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

yall-js

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

yall-js - npm Package Compare versions

Comparing version 3.1.7 to 3.2.0

.browserslistrc

123

dist/yall.js

@@ -12,2 +12,3 @@ 'use strict';

const events = options.events || {};
const noPolyfill = options.noPolyfill || false;

@@ -18,4 +19,6 @@ // Shorthands (saves more than a few bytes!)

const io = "IntersectionObserver";
const ioSupport = io in win && `${io}Entry` in win;
// App stuff
const crawler = /baidu|(?:google|bing|yandex|duckduck)bot/i.test(navigator.userAgent);
const dataAttrs = ["srcset", "src", "poster"];

@@ -28,19 +31,13 @@ const arr = [];

const parentNode = element.parentNode;
let sourceNode;
if (parentNode.nodeName == "PICTURE") {
sourceNode = parentNode;
yallApplyFn(queryDOM("source", parentNode), yallFlipDataAttrs);
}
if (element.nodeName == "VIDEO") {
sourceNode = element;
yallApplyFn(queryDOM("source", element), yallFlipDataAttrs);
}
yallApplyFn(queryDOM("source", sourceNode), yallFlipDataAttrs);
yallFlipDataAttrs(element);
if (element.autoplay) {
element.load();
}
const classList = element.classList;

@@ -62,41 +59,23 @@

// Added because there was a number of patterns like this peppered throughout
// the code. This just flips necessary data- attrs on an element
// the code. This flips necessary data- attrs on an element and prompts video
// elements to begin playback automatically if they have autoplay specified.
const yallFlipDataAttrs = element => {
for (let dataAttrIndex in dataAttrs) {
if (dataAttrs[dataAttrIndex] in element.dataset) {
win["requestAnimationFrame"](() => {
element.setAttribute(dataAttrs[dataAttrIndex], element.dataset[dataAttrs[dataAttrIndex]]);
});
}
}
};
element.setAttribute(dataAttrs[dataAttrIndex], element.dataset[dataAttrs[dataAttrIndex]]);
const parentNode = element.parentNode;
// Noticed lots of loops where a function simply gets executed on every
// member of an array. This abstraction eliminates that repetiive code.
const yallApplyFn = (items, fn) => {
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
fn instanceof win[io] ? fn.observe(items[itemIndex]) : fn(items[itemIndex]);
}
};
if (element.nodeName === "SOURCE" && parentNode.autoplay) {
parentNode.load();
const yallIntersectionObserve = entry => {
if (entry.isIntersecting || entry.intersectionRatio) {
const element = entry.target;
// For some reason, IE11 needs to have this method invoked in order
// for autoplay to start. So we do a yucky user agent check.
if (/Trident/.test(navigator.userAgent)) {
parentNode.play();
}
if (ric in win && idleLoadTimeout) {
win[ric](() => {
yallLoad(element);
}, {
timeout: idleLoadTimeout
});
} else {
yallLoad(element);
}
parentNode.classList.remove(lazyClass);
}
element.classList.remove(lazyClass);
intersectionListener.unobserve(element);
lazyElements = lazyElements.filter(lazyElement => lazyElement != element);
if (!lazyElements.length && !observeChanges) {
intersectionListener.disconnect();
element.classList.remove(lazyClass);
}

@@ -106,7 +85,7 @@ }

const yallMutationObserve = newElement => {
if (lazyElements.indexOf(newElement) < 0) {
lazyElements.push(newElement);
yallBindEvents(newElement);
intersectionListener.observe(newElement);
// Noticed lots of loops where a function simply gets executed on every
// member of an array. This abstraction eliminates that repetitive code.
const yallApplyFn = (items, fn) => {
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
win[io] && fn instanceof win[io] ? fn.observe(items[itemIndex]) : fn(items[itemIndex]);
}

@@ -117,3 +96,14 @@ };

new MutationObserver(() => {
yallApplyFn(queryDOM(), yallMutationObserve);
yallApplyFn(queryDOM(), newElement => {
if (lazyElements.indexOf(newElement) < 0) {
lazyElements.push(newElement);
yallBindEvents(newElement);
if (ioSupport && !crawler) {
intersectionListener.observe(newElement);
} else if (noPolyfill || crawler) {
yallApplyFn(lazyElements, yallLoad);
}
}
});
}).observe(entry, options.mutationObserverOptions || {

@@ -127,13 +117,33 @@ childList: true,

// If the current user agent is a known crawler, immediately load all media
// for the elements yall is listening for and halt execution (good for SEO).
if (/baidu|(?:google|bing|yandex|duckduck)bot/i.test(navigator.userAgent)) {
yallApplyFn(lazyElements, yallLoad);
yallApplyFn(lazyElements, yallBindEvents);
return;
}
// First we check if IntersectionObserver is supported. If not, we check to
// see if the `noPolyfill` option is set. If so, we load everything. If the
// current user agent is a known crawler, again, we load everything.
if (ioSupport && !crawler) {
var intersectionListener = new win[io](entries => {
yallApplyFn(entries, entry => {
if (entry.isIntersecting || entry.intersectionRatio) {
const element = entry.target;
if (io in win && `${io}Entry` in win) {
var intersectionListener = new win[io](entries => {
yallApplyFn(entries, yallIntersectionObserve);
if (ric in win && idleLoadTimeout) {
win[ric](() => {
yallLoad(element);
}, {
timeout: idleLoadTimeout
});
} else {
yallLoad(element);
}
intersectionListener.unobserve(element);
lazyElements = lazyElements.filter(lazyElement => lazyElement != element);
// If all the elements that were detected at load time are all loaded
// and we're not observing for changes, we're all done here.
if (!lazyElements.length && !observeChanges) {
intersectionListener.disconnect();
}
}
});
}, {

@@ -143,3 +153,2 @@ rootMargin: `${"threshold" in options ? options.threshold : 200}px 0%`

yallApplyFn(lazyElements, yallBindEvents);
yallApplyFn(lazyElements, intersectionListener);

@@ -150,2 +159,4 @@

}
} else if (noPolyfill || crawler) {
yallApplyFn(lazyElements, yallLoad);
}

@@ -152,0 +163,0 @@ }

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

var yall=function(){"use strict";return function(e){var n=(e=e||{}).lazyClass||"lazy",t=e.lazyBackgroundClass||"lazy-bg",o="idleLoadTimeout"in e?e.idleLoadTimeout:200,i=e.observeChanges||!1,r=e.events||{},a=window,s="requestIdleCallback",u="IntersectionObserver",c=["srcset","src","poster"],d=[],l=function(e,o){return d.slice.call((o||document).querySelectorAll(e||"img."+n+",video."+n+",iframe."+n+",."+t))},f=function(n){var o,i=n.parentNode;"PICTURE"==i.nodeName&&(o=i),"VIDEO"==n.nodeName&&(o=n),g(l("source",o),b),b(n),n.autoplay&&n.load();var r=n.classList;r.contains(t)&&(r.remove(t),r.add(e.lazyBackgroundLoaded||"lazy-bg-loaded"))},v=function(e){for(var n in r)e.addEventListener(n,r[n].listener||r[n],r[n].options||void 0)},b=function(e){var n=function(n){c[n]in e.dataset&&a.requestAnimationFrame((function(){e.setAttribute(c[n],e.dataset[c[n]])}))};for(var t in c)n(t)},g=function(e,n){for(var t=0;t<e.length;t++)n instanceof a[u]?n.observe(e[t]):n(e[t])},m=function(e){if(e.isIntersecting||e.intersectionRatio){var t=e.target;s in a&&o?a[s]((function(){f(t)}),{timeout:o}):f(t),t.classList.remove(n),p.unobserve(t),(h=h.filter((function(e){return e!=t}))).length||i||p.disconnect()}},y=function(e){h.indexOf(e)<0&&(h.push(e),v(e),p.observe(e))},h=l();if(/baidu|(?:google|bing|yandex|duckduck)bot/i.test(navigator.userAgent))g(h,f);else if(u in a&&u+"Entry"in a){var p=new a[u]((function(e){g(e,m)}),{rootMargin:("threshold"in e?e.threshold:200)+"px 0%"});g(h,v),g(h,p),i&&g(l(e.observeRootSelector||"body"),(function(n){new MutationObserver((function(){g(l(),y)})).observe(n,e.mutationObserverOptions||{childList:!0,subtree:!0})}))}}}();
var yall=function(){"use strict";return function(e){var n=(e=e||{}).lazyClass||"lazy",t=e.lazyBackgroundClass||"lazy-bg",o="idleLoadTimeout"in e?e.idleLoadTimeout:200,i=e.observeChanges||!1,r=e.events||{},a=e.noPolyfill||!1,s=window,c="requestIdleCallback",u="IntersectionObserver",l=u in s&&u+"Entry"in s,d=/baidu|(?:google|bing|yandex|duckduck)bot/i.test(navigator.userAgent),v=["srcset","src","poster"],f=[],queryDOM=function(e,o){return f.slice.call((o||document).querySelectorAll(e||"img."+n+",video."+n+",iframe."+n+",."+t))},yallLoad=function(n){var o=n.parentNode;"PICTURE"==o.nodeName&&yallApplyFn(queryDOM("source",o),yallFlipDataAttrs),"VIDEO"==n.nodeName&&yallApplyFn(queryDOM("source",n),yallFlipDataAttrs),yallFlipDataAttrs(n);var i=n.classList;i.contains(t)&&(i.remove(t),i.add(e.lazyBackgroundLoaded||"lazy-bg-loaded"))},yallBindEvents=function(e){for(var n in r)e.addEventListener(n,r[n].listener||r[n],r[n].options||void 0)},yallFlipDataAttrs=function(e){for(var t in v)if(v[t]in e.dataset){e.setAttribute(v[t],e.dataset[v[t]]);var o=e.parentNode;"SOURCE"===e.nodeName&&o.autoplay&&(o.load(),/Trident/.test(navigator.userAgent)&&o.play(),o.classList.remove(n)),e.classList.remove(n)}},yallApplyFn=function(e,n){for(var t=0;t<e.length;t++)s[u]&&n instanceof s[u]?n.observe(e[t]):n(e[t])},b=queryDOM();if(yallApplyFn(b,yallBindEvents),l&&!d){var g=new s[u]((function(e){yallApplyFn(e,(function(e){if(e.isIntersecting||e.intersectionRatio){var n=e.target;c in s&&o?s[c]((function(){yallLoad(n)}),{timeout:o}):yallLoad(n),g.unobserve(n),(b=b.filter((function(e){return e!=n}))).length||i||g.disconnect()}}))}),{rootMargin:("threshold"in e?e.threshold:200)+"px 0%"});yallApplyFn(b,g),i&&yallApplyFn(queryDOM(e.observeRootSelector||"body"),(function(n){new MutationObserver((function(){yallApplyFn(queryDOM(),(function(e){b.indexOf(e)<0&&(b.push(e),yallBindEvents(e),l&&!d?g.observe(e):(a||d)&&yallApplyFn(b,yallLoad))}))})).observe(n,e.mutationObserverOptions||{childList:!0,subtree:!0})}))}else(a||d)&&yallApplyFn(b,yallLoad)}}();
{
"name": "yall-js",
"version": "3.1.7",
"version": "3.2.0",
"description": "Yet Another Lazy Loader",

@@ -9,7 +9,8 @@ "main": "./dist/yall.js",

"scripts": {
"clean": "rm -rf ./dist",
"clean": "npx rimraf ./dist",
"lint": "npx eslint ./src/yall.mjs",
"test": "npm run lint && npm run build && cp -fv ./dist/yall.min.js ./test/js && npm run server",
"server": "node http.js",
"build": "npm run clean && npx rollup -c"
"build": "npm run clean && npx rollup -c",
"postinstall": "node -e \"console.log('\\u001b[31m\\u001b[1mThanks for using yall.js! Excluding bugfixes, development of yall.js is finished. You should also consider replacing yall.js with native lazy loading if you can. Learn more at \\u001b[34mhttps://web.dev/native-lazy-loading/\\u001b[0m')\""
},

@@ -42,12 +43,14 @@ "repository": {

"devDependencies": {
"@babel/cli": "^7.6.0",
"@babel/core": "^7.6.0",
"@babel/preset-env": "^7.6.0",
"eslint": "^6.4.0",
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.0",
"eslint": "^6.8.0",
"express": "^4.17.1",
"rollup": "^1.21.4",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-terser": "^5.1.2"
"rimraf": "^3.0.2",
"rollup": "^2.3.2",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-copy": "^3.3.0",
"rollup-plugin-terser": "^5.3.0"
},
"dependencies": {}
}

@@ -16,4 +16,6 @@ # yall.js (Yet Another Lazy Loader)

yall.js is a featured-packed SEO-friendly lazy loader for `<img>`, `<picture>`, `<video>` and `<iframe>` elements, as well as CSS background images. It works in all modern browsers, including IE 11. It uses [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) where available, but as of version 3, this API must be polyfilled for older browsers. It can also monitor the DOM for changes using [Mutation Observer](https://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/) to lazy load elements that have been appended to the DOM after initial load, which may be desirable for single page applications. It can also optimize use of browser idle time using [`requestIdleCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback), and reduce jank by using [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame).
**Note: Barring any bugfixes, development of yall.js is done. Additionally, consider using [native lazy loading](https://web.dev/native-lazy-loading/) instead of any JavaScript-based solution unless you need to lazy load resources other than images and iframes.**
yall.js is a featured-packed SEO-friendly lazy loader for `<img>`, `<picture>`, `<video>` and `<iframe>` elements, as well as CSS background images. It works in all modern browsers, including IE 11. It uses [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) where available, but as of version 3, this API must be polyfilled for older browsers. It can also monitor the DOM for changes using [Mutation Observer](https://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/) to lazy load elements that have been appended to the DOM after initial load, which may be desirable for single page applications. It can also optimize use of browser idle time using [`requestIdleCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback), and reduces jank by using [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame).
To use yall, grab `yall.min.js` (or `yall.min.mjs` if you're the modern sort) from the `dist` directory and slap it on your page. You can also install it with npm:

@@ -100,3 +102,3 @@

The pattern is largely the same as it is with `<picture>`, only the `lazy` class is applied to the `<video>` element. **Tip:** If you're embedding videos that _don't_ emulate animated GIFs (i.e., non autoplaying video), it's better to _not_ lazy load them. Instead, use the [`preload` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attr-preload) to defer loading of video content. Please also note that video autoplay policies can change at any time, meaning your video may not autoplay on some platforms! Such behaviors are not bugs, but rather features designed to conserve the user's bandwidth and preferences. Filing issues related to video autoplay issues will likely be rejected, as yall.js can't (and won't) override browser policies.
The pattern is largely the same as it is with `<picture>`, only the `lazy` class is applied to the `<video>` element. **Tip:** If you're embedding videos that _don't_ emulate animated GIFs (i.e., non autoplaying video), it's better to _not_ lazy load them. Instead, use the [`preload` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attr-preload) to defer loading of video content. Please also note that video autoplay policies can change at any time, meaning your video may not autoplay on some platforms! Such behaviors are not bugs, but rather features designed to respect users' bandwidth and preferences. Filing issues related to video autoplay issues will likely be rejected, as yall.js can't (and won't) override browser policies.

@@ -120,3 +122,3 @@ #### Lazy-loading `poster` placeholder images for non-autoplaying video

**Note:** For the sake of your users, don't mix the above markup patterns. If a video is going to use `autoplay` to replace an animated image, lazy loading a placeholder image via `data-poster` isn't necessary. Furthermore, if you're unsure of what to do, _let the browser handle this stuff and don't use yall.js to manage loading of videos_.
**Note:** For the sake of your users, don't mix the above markup patterns. If a video is going to use `autoplay` to replace an animated image, lazy loading a placeholder image via `data-poster` isn't necessary. Furthermore, if you're unsure of what to do, _let browsers handle this stuff and don't use yall.js to manage loading of videos at all!_

@@ -292,3 +294,3 @@ ### `<iframe>`

The advantage of this approach is that you can do pretty much anything you want in any of the events on the elements yall.js observes. The disadvantage is that it places the responsibility squarely on you to manage events. If you think yall.js has a bug in this behavior, do your due diligence to research whether your event callback code is buggy before filing an issue.
The advantage of this approach is that you can do pretty much anything you want in any of the events on the elements yall.js observes. The disadvantage is that it places the responsibility squarely on you to manage events. If you think yall.js has a bug in this behavior, do your due diligence to research whether your event callback code is buggy before filing issues.

@@ -298,3 +300,3 @@ ### `observeChanges`

**default:** `false`<br>
Use a `MutationObserver` to monitor the DOM for changes. This is useful if you're using yall.js in a single page application and want to lazy load resources for markup injected into the page after initial page render. _**Note:** This option will throw an error if enabled in a browser that doesn't support IntersectionObserver!_
Use a `MutationObserver` to monitor the DOM for changes. This is useful if you're using yall.js in a single page application and want to lazy load resources for markup injected into the page after initial page render.

@@ -309,4 +311,9 @@ ### `observeRootSelector`

**default:** `{ childList: true, subtree: true }`<br>
Options to pass to the `MutationObserver` instance. Read [this MDN guide](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver#MutationObserverInit) for a list of options.
Options to pass to the `MutationObserver` instance. Read [this MDN guide](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver#MutationObserverInit) for a list of options. It's very possible that changing this value could result in yall.js failing to lazy load resources that are appended to the DOM later on.
### `noPolyfill`
**default:** false
If `noPolyfill` is set to `true` yall.js will assume you are not polyfilling `IntersectionObserver`, and will subsequently load all resources when it detects no support for `IntersectionObserver`. This option will save you ~2.4kB for the `intersection-observer` polyfill, but be advised that invoking this option means that you could potentially load both placeholders _and_ the final image sources. Additionally, you'll be dependent on JavaScript to trigger immediate loading of all images in the document for browsers that don't support `IntersectionObserver`. For these reasons, it's only advised to enable this option if the vast majority of your users are on browsers that support `IntersectionObserver`.
## Words of advice

@@ -316,3 +323,3 @@

Also, it is not this script's job to minimize layout shifting for you. Use appropriate `width` and `height` attributes, styles, and lightweight placeholders for your images.
Also, it is not this script's job to minimize layout shifting for you. [Use appropriate `width` and `height` attributes](https://www.smashingmagazine.com/2020/03/setting-height-width-images-important-again/), styles, and lightweight placeholders for your images.

@@ -323,2 +330,8 @@ In the case of `<video>`, avoid lazy loading a placeholder with the `data-poster` attribute for autoplaying videos and just use `poster`. On the other hand, _do_ consider lazy loading a placeholder image with `data-poster` for non-autoplaying videos. Or you can opt _not_ to use a `poster` image. Your website, your call.

## Integration
Here are some external libraries or extensions built on top `malchata/yall.js`.
- [`adhocore/twig-yall`](https://github.com/adhocore/twig-yall) - A twig template engine extension that makes integration of `malchata/yall.js` a breeze.
## Contributing

@@ -328,3 +341,3 @@

- [Lozas.js](https://github.com/ApoorvSaxena/lozad.js)
- [Lozad.js](https://github.com/ApoorvSaxena/lozad.js)
- [lazysizes](https://github.com/aFarkas/lazysizes)

@@ -331,0 +344,0 @@

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