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

@shopkit/asset-cache

v1.0.0

Published

Browser-side asset caching solution with service worker integration, intelligent caching strategies, and Next.js components for optimal performance in e-commerce storefronts

Readme

@shopkit/asset-cache

A comprehensive browser-side asset caching solution providing intelligent caching strategies, service worker integration, and Next.js components for optimal performance in e-commerce storefronts.

Features

  • 🚀 Intelligent Caching: Multiple caching strategies (cache-first, network-first, stale-while-revalidate)
  • 🔄 Service Worker Integration: Offline support and background asset management
  • Next.js Components: Drop-in replacements for images and media with built-in caching
  • 🏷️ Tag-based Invalidation: Efficient cache invalidation using tags
  • 📦 Version Management: Content-based versioning for reliable cache invalidation
  • 🎯 TypeScript Support: Full type safety and IntelliSense support
  • 🔧 Configurable: Flexible configuration options for different use cases

Installation

npm install @shopkit/asset-cache
# or
yarn add @shopkit/asset-cache
# or
bun add @shopkit/asset-cache

Quick Start

1. Initialize the Asset Cache

import { initAssetCache } from '@shopkit/asset-cache';

// Initialize with default settings
await initAssetCache();

// Or with custom configuration
await initAssetCache({
  storageName: 'my-app-cache',
  serviceWorkerEnabled: true,
  serviceWorkerPath: '/custom-sw.js', // Custom service worker path
  manifestPath: '/cache-manifest.json', // Custom manifest path
  debug: true,
  maxSize: 100, // 100MB cache size
  maxAge: 604800 // 7 days TTL
});

2. Use with Next.js

The package includes Next.js integration templates in the templates/nextjs-integration/ folder. Copy these files to your project:

# Copy the Next.js integration files to your project
cp -r node_modules/@shopkit/asset-cache/templates/nextjs-integration/* ./src/lib/asset-cache/

Then use the components:

import { AssetCacheInitializer, AssetCacheImage } from './lib/asset-cache';

// In your app layout
export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <AssetCacheInitializer
          storageName="my-app-cache"
          serviceWorkerEnabled={true}
          debug={process.env.NODE_ENV === 'development'}
          maxSize={100}
          onInitialized={() => console.log('Asset cache ready!')}
          onError={(error) => console.error('Cache init failed:', error)}
        />
        {children}
      </body>
    </html>
  );
}

// Or with default settings
export default function SimpleLayout({ children }) {
  return (
    <html>
      <body>
        <AssetCacheInitializer />
        {children}
      </body>
    </html>
  );
}

// In your components
export function ProductImage({ src, alt }) {
  return (
    <AssetCacheImage
      src={src}
      alt={alt}
      width={300}
      height={300}
      cacheOptions={{
        ttl: 7 * 24 * 60 * 60, // 7 days
        tags: ['product-images'],
        priority: 'high'
      }}
    />
  );
}

3. Manual Asset Loading

import { AssetLoader } from '@shopkit/asset-cache';

// Preload an asset
await AssetLoader.preload('/images/hero.jpg', {
  ttl: 3600, // 1 hour
  tags: ['hero-images']
});

// Load an asset with caching
const result = await AssetLoader.load('/images/product.jpg');
if (result.success) {
  console.log('Loaded from:', result.fromCache ? 'cache' : 'network');
  // Use result.data (Blob)
}

// Check if an asset is cached
const isCached = await AssetLoader.isCached('/images/product.jpg');

// Invalidate specific assets
await AssetLoader.invalidate('/images/old-product.jpg');

// Invalidate by tag
await AssetLoader.invalidateByTag('product-images');

API Reference

Core Classes

AssetLoader

The main class for loading and managing cached assets.

class AssetLoader {
  static async init(config?: AssetLoaderConfig): Promise<void>
  static async preload(url: string, options?: CacheOptions): Promise<void>
  static async load<T>(url: string, options?: CacheOptions): Promise<CacheResult<T>>
  static async isCached(url: string): Promise<boolean>
  static async invalidate(url: string): Promise<void>
  static async invalidateByTag(tag: string): Promise<void>
}

CacheManager

Manages cache storage and metadata.

class CacheManager {
  static async init(cacheName?: string): Promise<void>
  static async addToManifest(url: string, metadata: AssetMetadata): Promise<void>
  static async getAssetMetadata(url: string): Promise<AssetMetadata | null>
  static async removeFromManifest(url: string): Promise<void>
  static async getAssetsByTag(tag: string): Promise<AssetMetadata[]>
}

VersionManager

Handles asset versioning and cache invalidation.

class VersionManager {
  static init(deploymentId?: string): void
  static createVersionedUrl(url: string): string
  static hasVersion(url: string): boolean
  static extractVersion(url: string): string | null
}

Configuration

AssetCacheConfig

interface AssetCacheConfig {
  enabled?: boolean;            // Default: true - Enable/disable asset cache
  version?: string;             // Default: '1.0.0' - Cache version for invalidation
  debug?: boolean;              // Default: false - Enable debug logging
  storageName?: string;         // Default: 'asset-cache-v1' - Cache storage name
  maxSize?: number;             // Default: 50 - Maximum cache size in MB
  maxAge?: number;              // Default: 86400 - Maximum age in seconds (24 hours)
  serviceWorkerEnabled?: boolean; // Default: true - Enable service worker
  serviceWorkerPath?: string;   // Default: '/sw.js' - Service worker file path
  manifestPath?: string;        // Default: '/manifest.json' - Cache manifest file path
}

CacheOptions

interface CacheOptions {
  ttl?: number;                 // Time to live in seconds
  revalidate?: boolean;         // Whether to revalidate on access
  tags?: string[];              // Cache tags for invalidation
  priority?: 'high' | 'medium' | 'low'; // Priority for preloading
}

Next.js Integration

Components

// Asset Cache Initializer Component
<AssetCacheInitializer
  storageName="my-app-cache"        // Custom cache name
  serviceWorkerEnabled={true}       // Enable service worker
  debug={false}                     // Enable debug logging
  version="v1.2.3"                 // Cache version for invalidation
  maxSize={100}                     // Maximum cache size in MB
  maxAge={604800}                   // Maximum age in seconds (7 days)
  onInitialized={() => {}}          // Success callback
  onError={(error) => {}}           // Error callback
/>

// Cached Image Component
<AssetCacheImage
  src="/image.jpg"
  alt="Description"
  width={300}
  height={200}
  cacheOptions={{
    ttl: 3600,
    tags: ['images'],
    priority: 'high'
  }}
/>

// Cached Video Component
<AssetCacheVideo
  src="/video.mp4"
  width={640}
  height={360}
  cacheOptions={{
    ttl: 7200,
    tags: ['videos']
  }}
/>

Hooks

// Image caching hook
const { src, loading, error } = useAssetCacheImage('/image.jpg', {
  ttl: 3600,
  tags: ['images']
});

// Video caching hook
const { src, loading, error } = useAssetCacheVideo('/video.mp4', {
  ttl: 7200,
  tags: ['videos']
});

// Asset preloading hook
useAssetCachePreload([
  { url: '/image1.jpg', options: { tags: ['hero'] } },
  { url: '/image2.jpg', options: { tags: ['products'] } }
]);

Caching Strategies

The package includes three built-in caching strategies:

Cache First

Serves from cache if available, falls back to network.

import { cacheFirstStrategy } from '@shopkit/asset-cache/strategies';

const response = await cacheFirstStrategy(request, cacheName);

Network First

Tries network first, falls back to cache if network fails.

import { networkFirstStrategy } from '@shopkit/asset-cache/strategies';

const response = await networkFirstStrategy(request, cacheName);

Stale While Revalidate

Serves from cache immediately, updates cache in background.

import { staleWhileRevalidateStrategy } from '@shopkit/asset-cache/strategies';

const response = await staleWhileRevalidateStrategy(request, cacheName);

Service Worker Integration

The package automatically registers and manages a service worker for enhanced caching capabilities:

import { 
  registerServiceWorker, 
  isServiceWorkerActive,
  sendMessageToSW 
} from '@shopkit/asset-cache/core';

// Register service worker
await registerServiceWorker('/sw.js');

// Check if active
if (isServiceWorkerActive()) {
  // Send message to service worker
  await sendMessageToSW('CACHE_ASSET', { url: '/image.jpg' });
}

Cache Invalidation

By URL

await AssetLoader.invalidate('/specific-image.jpg');

By Tags

// Invalidate all product images
await AssetLoader.invalidateByTag('product-images');

// Invalidate multiple tags
await AssetLoader.invalidateByTag('hero-images');
await AssetLoader.invalidateByTag('banner-images');

Version-based

Assets are automatically versioned using content hashes, ensuring cache invalidation when content changes.

Performance Considerations

  • Selective Caching: Only cache assets that benefit from caching
  • Size Limits: Configurable maximum size limits for cached assets
  • TTL Management: Flexible time-to-live settings per asset type
  • Storage Quotas: Automatic monitoring of browser storage limits
  • Background Updates: Stale-while-revalidate for optimal performance

Browser Support

  • Chrome 40+
  • Firefox 44+
  • Safari 11.1+
  • Edge 17+

Requires support for:

  • Service Workers
  • Cache API
  • IndexedDB
  • Fetch API

Templates

The package includes ready-to-use templates for popular frameworks:

Next.js Integration (templates/nextjs-integration/)

Complete Next.js integration with:

  • AssetCacheInitializer.tsx - Component for app initialization
  • AssetCachedImage.tsx - Drop-in replacement for Next.js Image (AssetCacheImage component, useAssetCacheImage hook)
  • AssetCachedVideo.tsx - Cached video component (AssetCacheVideo component, useAssetCacheVideo hook)
  • usePreloadAssets.ts - Hook for asset preloading (useAssetCachePreload)
  • initializeAssetCache.ts - Initialization utilities
  • nextjsConfig.ts - Next.js specific configuration
  • index.ts - Main exports file

Vanilla JavaScript (templates/vanilla-javascript/)

Basic implementation examples:

  • basicAssetCaching.ts - Simple asset caching implementation
  • README.md - Usage instructions

Examples

E-commerce Product Gallery

import { AssetLoader } from '@shopkit/asset-cache';

// Preload product images
const productImages = [
  '/products/shoe-1.jpg',
  '/products/shoe-2.jpg',
  '/products/shoe-3.jpg'
];

await Promise.all(
  productImages.map(url => 
    AssetLoader.preload(url, {
      ttl: 24 * 60 * 60, // 24 hours
      tags: ['product-gallery'],
      priority: 'high'
    })
  )
);

Dynamic Content Updates

// When products are updated, invalidate related caches
await AssetLoader.invalidateByTag('product-images');
await AssetLoader.invalidateByTag('product-thumbnails');

// Preload new content
await AssetLoader.preload('/new-product-image.jpg', {
  tags: ['product-images']
});

Contributing

See CONTRIBUTING.md for development setup and contribution guidelines.

License

MIT License - see LICENSE file for details.