@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
Maintainers
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-cacheQuick 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 initializationAssetCachedImage.tsx- Drop-in replacement for Next.js Image (AssetCacheImagecomponent,useAssetCacheImagehook)AssetCachedVideo.tsx- Cached video component (AssetCacheVideocomponent,useAssetCacheVideohook)usePreloadAssets.ts- Hook for asset preloading (useAssetCachePreload)initializeAssetCache.ts- Initialization utilitiesnextjsConfig.ts- Next.js specific configurationindex.ts- Main exports file
Vanilla JavaScript (templates/vanilla-javascript/)
Basic implementation examples:
basicAssetCaching.ts- Simple asset caching implementationREADME.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.
