npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

lazy-viewport-loader

v1.0.2

Published

Lazy load functions when elements enter viewport using IntersectionObserver

Readme

lazy-viewport-loader

Boost your website performance by lazy-loading heavy JavaScript functions only when they're needed.

Stop loading everything upfront. Load modules only when users scroll to them.

The Problem

You have a heavy JavaScript module (e.g., 400KB chart library, video player, map widget) that slows down your initial page load. Users might never even scroll to that section, but you're forcing them to download it anyway.

The Solution

lazy-viewport-loader uses IntersectionObserver to load JavaScript modules only when the target element enters the viewport. This dramatically improves initial load time and performance scores.

Installation

npm install lazy-viewport-loader

Quick Example

import { useLoadFunction } from 'lazy-viewport-loader'

// Load a 400KB chart library only when user scrolls to #chart-container
useLoadFunction(
  () => import('./heavyChartLibrary.js'), // 400KB module
  '#chart-container',                      // Target element
  [chartData, chartOptions]                // Arguments to pass
)

Result: The heavy module is downloaded and executed only when #chart-container becomes visible.

Usage Examples

Basic Usage

import { useLoadFunction } from 'lazy-viewport-loader'

// Load analytics when footer is visible
useLoadFunction(
  () => import('./analytics.js'),
  'footer'
)

With Arguments

// Load video player with configuration
useLoadFunction(
  () => import('./videoPlayer.js'),
  '#video-section',
  ['video-id-123', { autoplay: false, quality: 'hd' }]
)

Custom Intersection Options

// Load 200px before element enters viewport
useLoadFunction(
  () => import('./comments.js'),
  '#comments',
  [],
  { 
    threshold: 0,
    rootMargin: '200px' // Start loading 200px before visible
  }
)

Load at 50% Visibility

// Load when element is 50% visible
useLoadFunction(
  () => import('./gallery.js'),
  '#image-gallery',
  [images],
  { threshold: 0.5 }
)

Manual Control

const observer = useLoadFunction(
  () => import('./module.js'),
  '#target'
)

// Stop observing manually if needed
observer.stopObserving()

API

useLoadFunction(importFn, element, args, options)

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | importFn | Function | Yes | Dynamic import function (e.g., () => import('./module.js')) | | element | string | Yes | CSS selector for the element to observe | | args | Array | No | Arguments to pass to the imported function (default: []) | | options | IntersectionObserverInit | No | IntersectionObserver options (default: { threshold: 0, rootMargin: '100px' }) |

Returns

Observer instance with control methods:

  • stopObserving() - Manually stop observing the element

IntersectionObserver Options

  • threshold: Number between 0-1. 0 = any pixel visible, 1 = fully visible
  • rootMargin: Start loading before element is visible (e.g., '100px', '200px 0px')

Real-World Use Cases

📊 Heavy Chart Library (400KB+)

// Load Chart.js only when user scrolls to charts section
useLoadFunction(
  () => import('chart.js'),
  '#analytics-dashboard',
  [chartConfig]
)

🎥 Video Player (200KB+)

// Load video player library on-demand
useLoadFunction(
  () => import('./videoPlayer.js'),
  '.video-container',
  [videoUrl, playerOptions]
)

🗺️ Interactive Maps (500KB+)

// Load Google Maps/Leaflet only when map section is visible
useLoadFunction(
  () => import('./mapInitializer.js'),
  '#map-section',
  [coordinates, mapConfig],
  { rootMargin: '300px' } // Preload 300px before visible
)

💬 Comments Section

// Load comments widget when user scrolls down
useLoadFunction(
  () => import('./commentsWidget.js'),
  '#comments',
  [],
  { threshold: 0.25 } // Load when 25% visible
)

📸 Image Gallery with Heavy Dependencies

// Load image gallery library (lightbox, zoom, etc.)
useLoadFunction(
  () => import('./imageGallery.js'),
  '.gallery-grid',
  [images, galleryOptions]
)

Performance Benefits

Faster initial page load - Only load what's immediately visible
Lower bandwidth usage - Users don't download modules they never see
Better Core Web Vitals - Improved FCP, LCP, and TTI scores
Automatic cleanup - Observer stops after first trigger
Mobile-friendly - Especially beneficial for users on slow connections

Browser Support

Works in all modern browsers that support IntersectionObserver:

  • Chrome 51+
  • Firefox 55+
  • Safari 12.1+
  • Edge 15+

For older browsers, use an IntersectionObserver polyfill.

How It Works

  1. Observe: Watches when the target element enters the viewport
  2. Import: Dynamically imports the module when visible
  3. Execute: Calls the exported function with provided arguments
  4. Cleanup: Automatically stops observing after loading

Module Requirements

Your imported module should export a function as default or named export:

// module.js
export default function initializeFeature(arg1, arg2) {
  // Your code here
}

// or

export function initializeFeature(arg1, arg2) {
  // Your code here
}

License

MIT

Contributing

Issues and pull requests are welcome on GitHub.


Made with ⚡ for better web performance