How verlok/vanilla-lazyload works
1. This repository is a client-side JavaScript library, not an application server. Its core product is a LazyLoad class that defers loading of images, responsive images, background images, videos, iframes, SVG/object content, and even arbitrary functions until elements are near or inside the viewport.
2. The main runtime boundary is the src/ library code versus the dist/ published bundles. src/ is the authored source, while dist/esm, dist/lazyload.js, and dist/lazyload.iife.js are build outputs for ES modules, UMD, and IIFE consumers. The same architecture is preserved across these bundles.
3. The top-level orchestration lives in src/lazyload.js. It is the public API surface that wires together options, element discovery, observer setup, load triggers, lifecycle methods, and bookkeeping. From an architecture diagram perspective, this is the central controller.
4. Element discovery is based on a container + selector model. By default, the library scans descendants of a scrolling container for elements with the .lazy class, but both the container and the selector are configurable. This means the library supports the main document as well as nested scrolling panels as separate observation scopes.
5. The viewport detection path is built around IntersectionObserver. The intersectionObserver, intersectionHandlers, and unobserve modules appear to split observer setup, per-entry enter/exit handling, and cleanup. The data flow is: discovered elements are observed, intersection events fire, handlers decide whether to enter/exit/load/unobserve, and state is updated accordingly.
6. Actual loading is delegated to type-specific helpers. The load, set, forEachSource, and tempImage modules likely handle translating data-* attributes into real DOM attributes for different targets: img, picture/source, video/source, iframe, object, and background-image variants. This is the key content-loading boundary between lazy metadata and browser-recognized resource URLs.
7. The library maintains per-element state and original attributes so it can reverse changes later. data, originalAttributes, elementStatus, reset, and restore indicate that LazyLoad tracks whether an element is pending, loading, loaded, errored, entered, or exited, and can reset or restore DOM back to its initial state. That makes lifecycle management a first-class concern, especially for SPAs or retry flows.
8. There is explicit support for cancellation and error recovery. cancelOnExit handles abort-like behavior when an image leaves the viewport before finishing, while online suggests retry logic when network connectivity returns. Together these modules add a resilience layer around the basic “load on enter” behavior.
9. Native-lazy-loading support is a separate branch, not just a flag on the same code path. The native and environment modules indicate feature detection and a hybrid mode where the library can delegate supported img/iframe/video loading to the browser via loading="lazy", while still handling unsupported cases such as background images through the JS observer path.
10. The library exposes rich callbacks and DOM class hooks as its integration boundary. callback, event, class, and defaults suggest that consumers can react to enter/load/error/finish events and style loading states through configurable class names. This is the main way application code hooks into the internal pipeline without touching implementation details.
11. autoInitialize.js is the bridge for the “async script” usage model described in the README. It allows the library to self-start from global options and emit an initialization event, which is important for CDN deployments where code runs after the script tag loads instead of via direct construction.
12. The repo includes extensive verification and usage surfaces: unit tests for stateful helpers like load/reset/restore/set/cancel behavior, end-to-end Playwright tests for real browser loading scenarios, and many HTML demos that exercise each feature combination. That makes the architecture easy to validate across browser APIs and edge cases such as dynamic content, multiple containers, placeholders, and error handling.
13. Tooling is centered on packaging and browser compatibility rather than a server runtime: Rollup for bundling, Jest for unit tests, Playwright for browser E2E, and CI workflows in GitHub Actions. There is also a TypeScript declaration file in typings/, so the library is distributed with typed consumer support even though the source is plain JavaScript.
Main entry points: lazyload.js LazyLoad · load.js Load · rollup.config.mjs Rollup · intersectionHandlers.js Handlers
Components 26
Source
Authored library modules in src/.
- LazyLoad · Top-level controller that wires options, discovery, observation, loading, lifecycle, and cleanup.
src/lazyload.js - Defaults · Default options and integration hooks for consumers.
src/defaults.js - DOM scan · Container and selector-based element discovery inside scroll scopes.
src/dom.js - Observer · IntersectionObserver setup and element observation lifecycle.
src/intersectionObserver.js - Handlers · Per-entry enter/exit decisions and load triggering.
src/intersectionHandlers.js - Unobserve · Removes observed elements and finalizes observer cleanup.
src/unobserve.js - Load · Delegates resource loading for lazy elements and variants.
src/load.js - Set attrs · Translates lazy data attributes into live DOM attributes.
src/set.js - Sources · Iterates over picture/source descendants during load preparation.
src/forEachSource.js - Temp image · Temporary image handling used during staged loading and detection.
src/tempImage.js - State · Per-element data, status, counters, and original attributes.
src/data.js - Restore · Resets or restores elements back to their initial DOM state.
src/restore.js - Cancel exit · Aborts in-flight loading when elements leave the viewport.
src/cancelOnExit.js - Native mode · Feature detection and hybrid delegation to browser native lazy-loading.
src/native.js - Online · Network-recovery path for retrying failed or pending loads.
src/online.js - Auto init · Self-start bridge for script-tag and global-options usage.
src/autoInitialize.js
Bundles
Published build outputs in dist/.
- ESM bundle · ES module distribution bundle.
dist/esm/lazyload.js - UMD bundle · Browser-friendly bundle for module and script consumers.
dist/lazyload.js - IIFE bundle · Self-executing bundle for direct browser inclusion.
dist/lazyload.iife.js
Verification
Tests and browser demos that exercise the library.
- Unit tests · Stateful helper coverage for loading, restoring, and cancellation behavior.
tests/unit - E2E tests · Playwright scenarios for real browser lazy-loading flows.
tests/e2e - Demos · Interactive HTML scenarios covering images, media, backgrounds, containers, and async use.
demos
Tooling
Packaging, typing, and repository infrastructure.
- Types · TypeScript declarations for consumer integration.
typings/lazyload.d.ts - Rollup · Build pipeline that produces the distributed bundles.
rollup.config.mjs - Jest · Unit test runner configuration.
jest.config.cjs - Playwright · End-to-end browser test configuration.
playwright.config.js
Connections 25
- LazyLoad → Defaults: reads config · Initializes runtime behavior from default and consumer options.
- LazyLoad → DOM scan: discovers · Finds lazy elements within the configured container and selector.
- LazyLoad → Observer: starts observation · Sets up viewport observation for discovered elements.
- Observer → Handlers: emits entries · Feeds intersection events into enter/exit handling.
- Handlers → Load: triggers · Loads elements that become eligible in the viewport.
- Handlers → Unobserve: cleans up · Stops observing elements after completion or exit handling.
- Load → Set attrs: maps attrs · Converts data attributes into live resource attributes.
- Load → Sources: walks sources · Processes picture/source descendants during loading.
- Load → Temp image: uses preload · Leans on temporary image handling for staged loading.
- Load → State: updates state · Records loading progress and per-element bookkeeping.
- State → Restore: supports reset · Preserves originals so DOM can be restored later.
- State → Cancel exit: tracks inflight · Provides state for cancel-on-exit behavior.
- LazyLoad → Native mode: feature branch · Delegates supported elements to browser native lazy-loading when available.
- LazyLoad → Online: retry path · Reconnects loading logic after network recovery.
- LazyLoad → Auto init: bootstraps · Supports async script initialization from global options.
- LazyLoad → ESM bundle: published as · Source library is bundled into the ES module distribution.
- LazyLoad → UMD bundle: published as · Source library is bundled into the UMD distribution.
- LazyLoad → IIFE bundle: published as · Source library is bundled into the IIFE distribution.
- Rollup → ESM bundle: produces · Rollup generates the ES module build.
- Rollup → UMD bundle: produces · Rollup generates the browser UMD build.
- Rollup → IIFE bundle: produces · Rollup generates the IIFE build.
- Jest → Unit tests: runs · Jest executes unit-level helper tests.
- Playwright → E2E tests: runs · Playwright executes browser end-to-end scenarios.
- Demos → LazyLoad: exercises · Demo pages showcase the runtime API and feature combinations.
- Types → LazyLoad: types API · Declaration file describes the public JavaScript API.