Thanks to visit codestin.com
Credit goes to github.com

Skip to content

MoussaabBadla/react-shrink

Repository files navigation

React-Shrink

Blazing-fast client-side image compression library for React with Web Worker support

npm version npm downloads Bundle Size TypeScript License

Compress images in the browser | Reduce file sizes by 70-99% | WebP, AVIF, JPEG support | Zero dependencies

Intelligent image compression engine for React applications. Optimize images client-side before upload with adaptive quality algorithms, Web Worker parallelization, and automatic format selection. Perfect for React, Next.js, and Vite projects.

Quick Start Β· API Docs Β· Live Examples Β· Benchmarks


✨ Key Features

Image Compression & Optimization:

  • πŸš€ Web Worker Compression - Non-blocking, parallel image processing
  • 🎯 Adaptive Quality - Binary search algorithm meets exact size targets (300KB, 500KB, 1MB)
  • πŸ–ΌοΈ Modern Image Formats - WebP, AVIF, JPEG with automatic browser fallback
  • πŸ“‰ 70-99% Size Reduction - Proven compression ratios from real-world testing

Developer Experience:

  • πŸ“¦ Batch Image Processing - Compress multiple images concurrently
  • πŸ“± HEIC/HEIF Support - Convert iOS images (iPhone photos)
  • 🎨 PNG Transparency - Preserves alpha channels automatically
  • πŸ“Š Upload Progress Tracking - Real-time compression progress callbacks
  • πŸ”§ TypeScript First - Complete type definitions and IntelliSense
  • πŸͺΆ 5.8KB Gzipped - Minimal bundle size, zero dependencies
  • ⚑ React Hooks - Simple useShrink() hook for React integration

Production Ready:

  • βœ… Works with React, Next.js, Vite, Create React App
  • βœ… Browser image optimization before upload
  • βœ… Automatic format detection (JPEG, PNG, WebP, AVIF, HEIC)
  • βœ… Memory efficient processing
  • βœ… Works on mobile browsers (iOS Safari, Chrome Mobile)

πŸ“¦ Installation

Install via npm, yarn, or pnpm:

npm install react-shrink
# or
yarn add react-shrink
# or
pnpm add react-shrink

Optional: Add HEIC/HEIF support for iOS iPhone images:

npm install heic2any

Compatible with: React 16.8+, Next.js, Vite, Create React App, Remix, Gatsby

Verify installation:

npm list react-shrink

πŸš€ Quick Start

React Hook (Recommended)

import { useShrink } from 'react-shrink'

function ImageUploader() {
  const { shrink, isProcessing, progress } = useShrink()

  const handleFile = async (file: File) => {
    const result = await shrink(file, {
      maxKB: 300,  // Target 300KB or less
      maxEdge: 2048 // Max 2048px width/height
    })

    // Upload compressed blob
    await uploadToServer(result.blob)
  }

  return (
    <div>
      <input type="file" accept="image/*" onChange={e => handleFile(e.target.files[0])} />
      {isProcessing && <progress value={progress} max={100} />}
    </div>
  )
}

Standalone Function

import { shrink } from 'react-shrink'

const result = await shrink(imageFile, {
  maxKB: 500,
  codecs: ['webp', 'jpeg']
})

console.log(`Reduced from ${imageFile.size} to ${result.bytes} bytes`)

With Web Workers (Better Performance)

import { shrinkWithWorker } from 'react-shrink'

// Non-blocking compression - UI stays responsive
const result = await shrinkWithWorker(largeFile, { maxKB: 300 })

πŸ“– API

Core Functions

shrink(file, options?)

Main compression function. Runs on main thread.

const result = await shrink(file, {
  maxKB: 300,           // Target max size (KB)
  maxEdge: 2048,        // Max dimension (px)
  codecs: ['webp', 'jpeg'], // Preferred formats
  quality: 0.85,        // Fixed quality or auto
  useWorker: false      // Use web worker
})

Returns: ShrinkResult

{
  blob: Blob          // Compressed image
  bytes: number       // Final size
  width: number       // Final dimensions
  height: number
  mime: string        // Output format
  diagnostics: {
    ratio: number     // Compression ratio
    timeMs: number    // Processing time
    codec: string     // Used codec
    quality: number   // Applied quality
  }
}

shrinkWithWorker(file, options?)

Worker-based compression. Recommended for large files (>2MB).

  • Non-blocking UI
  • 50-80% faster for large images
  • Automatic worker pool management
  • Same API as shrink()

Requires: Chrome 69+, Firefox 105+, Safari 16.4+

shrinkBatch(files, options?)

Process multiple images concurrently.

const result = await shrinkBatch(files, {
  maxKB: 300,
  concurrency: 3,  // Parallel operations
  onProgress: (done, total) => console.log(`${done}/${total}`)
})

console.log(`Processed: ${result.successful}/${result.total}`)

React Hook

useShrink()

Stateful compression with automatic cleanup.

const {
  shrink,              // Compress single file
  shrinkBatch,         // Compress multiple files
  isProcessing,        // Current state
  progress,            // 0-100
  error,               // Last error
  result,              // Last result
  workerSupported,     // Worker availability
  reset                // Clear state
} = useShrink()

Auto-worker: Automatically uses workers for files >2MB when supported.

Configuration

Option Type Default Description
maxKB number 300 Target max file size (KB)
maxEdge number 2048 Max width/height (px)
codecs ImageCodec[] ['webp','jpeg'] Preferred formats
transparency 'keep'┃'remove' 'keep' Alpha channel handling
quality number auto Fixed quality 0-1
stripMetadata boolean true Remove EXIF data
useWorker boolean auto Enable web workers
onProgress function - Progress callback

Presets

Ready-made configurations for common scenarios:

import { PRESET_AVATAR, PRESET_GALLERY, PRESET_SOCIAL } from 'react-shrink'

await shrink(file, PRESET_AVATAR)  // 100KB, 512px
await shrink(file, PRESET_GALLERY) // 300KB, 2048px
await shrink(file, PRESET_SOCIAL)  // 500KB, 1920px

Available presets:

  • PRESET_THUMBNAIL - 50KB, 200px
  • PRESET_AVATAR - 100KB, 512px
  • PRESET_GALLERY - 300KB, 2048px
  • PRESET_HIGH_QUALITY - 1MB, 4096px
  • PRESET_SOCIAL - 500KB, 1920px
  • PRESET_DOCUMENT - 400KB, 2560px
  • PRESET_ECOMMERCE - 350KB, 2000px

Custom presets:

const custom = createPreset('gallery', { maxKB: 500, codecs: ['avif', 'webp'] })

πŸ’‘ Examples

Batch Upload

import { useShrink } from 'react-shrink'

function BatchUploader() {
  const { shrinkBatch } = useShrink()

  const handleFiles = async (files: File[]) => {
    const result = await shrinkBatch(files, {
      maxKB: 300,
      concurrency: 3,
      useWorker: true
    })

    console.log(`Saved ${result.totalBytesSaved} bytes`)
  }

  return <input type="file" multiple onChange={e => handleFiles([...e.target.files])} />
}

With Progress Bar

function ProgressExample() {
  const [progress, setProgress] = useState(0)

  const compress = async (file: File) => {
    await shrink(file, {
      maxKB: 300,
      onProgress: setProgress
    })
  }

  return <progress value={progress} max={100} />
}

Error Handling

import { ImageLoadError, CompressionError } from 'react-shrink'

try {
  const result = await shrink(file)
} catch (error) {
  if (error instanceof ImageLoadError) {
    alert('Invalid image file')
  } else if (error instanceof CompressionError) {
    alert('Compression failed')
  }
}

HEIC Support (iOS Photos)

import { shrink } from 'react-shrink'

// Automatic HEIC detection and conversion
const result = await shrink(iphotoFile, { maxKB: 300 })
// Works seamlessly if heic2any is installed

Advanced: Worker Pool

import { getWorkerPool, terminateWorkerPool } from 'react-shrink'

// Access worker pool directly
const pool = await getWorkerPool(4) // 4 workers
console.log(pool.getStats())

// Cleanup when done
terminateWorkerPool()

πŸ§ͺ Worker Support

Check browser compatibility:

import { canUseWorkerCompression, getOptimalWorkerCount } from 'react-shrink'

if (canUseWorkerCompression()) {
  console.log(`Workers available: ${getOptimalWorkerCount()}`)
}

Browser Requirements:

  • OffscreenCanvas API
  • Transferable ImageBitmap
  • Worker API

Supported:

  • Chrome 69+
  • Firefox 105+
  • Safari 16.4+
  • Edge 79+

🎯 Performance

Real-World Benchmarks

Tested on MacBook Air M2 2022, Chrome browser, WebP compression with maxKB: 300:

Resolution Input Size Output Size Reduction Time
3024Γ—4032 1.93 MB 211 KB 89% 699ms
4320Γ—4320 12.63 MB 111 KB 99% 716ms
1024Γ—1024 670 KB 15.7 KB 98% 105ms

πŸ”§ Utilities

Low-level functions for advanced use:

import {
  calculateNewDimensions,
  hasAlphaChannel,
  isCodecSupported,
  getMimeType
} from 'react-shrink'

// Dimension calculations
const { width, height } = calculateNewDimensions(1920, 1080, 1024)

// Codec detection
const avifSupported = await isCodecSupported('avif')

🌐 Browser Support

Feature Chrome Firefox Safari Edge
Core 60+ 55+ 12+ 79+
WebP 32+ 65+ 14+ 18+
AVIF 85+ 93+ 16+ 93+
Workers 69+ 105+ 16.4+ 79+

πŸ› οΈ Development

# Install dependencies
npm install

# Run demo
npm run dev

# Build library
npm run build

# Run tests
npm test

# Type check
npm run typecheck

# Lint & format
npm run lint
npm run format

🎯 Use Cases

Perfect for:

  • πŸ“Έ Image upload forms - Reduce upload times and server bandwidth
  • πŸ–ΌοΈ Photo galleries - Optimize multiple images before upload
  • πŸ‘€ Profile picture uploads - Compress avatars and profile photos
  • πŸ›’ E-commerce platforms - Product image optimization
  • πŸ“± Mobile-first apps - Reduce data usage on mobile networks
  • πŸ“ Content management systems - CMS image optimization
  • πŸ’¬ Social media apps - Compress user-generated content
  • πŸ“Š File upload widgets - React file uploader with compression

License

MIT Β© 2025 Badla Moussaab

Contributing

Contributions are welcome! Help improve React-Shrink:

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

🌟 Support

If React-Shrink helps your project:

πŸ”— Links