WebAssembly를 사용하여 Next.js에서 100% 클라이언트 측 8MB 비디오 압축기를 구축한 방법

작성자

카테고리:

← 피드로
DEV Community · Anass Laribi · 2026-09-09 개발(SW)

Anass Laribi

Online video compressors are usually frustrating: you have to upload a 100MB personal video to a remote cloud server, wait in an artificial processing queue, deal with intrusive popup ads, and download a watermarked video.

I wanted to see if modern browser technology was fast enough to run desktop-grade video compression entirely on the user’s computer with zero server uploads.

Here is the technical breakdown of how I built clipshrink.com using Next.js 16, React 19, and FFmpeg compiled to WebAssembly (WASM).

  1. The Architecture: In-Browser Sandboxing

Traditional cloud tools rely on multi-core backend server clusters. ClipShrink takes the opposite approach: **0 bytes ever leave the user’s device.

[User Selects Video (.mp4, .mov, .webm)]
│
▼
[Local Browser RAM Sandbox] ◄─── (0 bytes sent to external cloud servers)
│
▼
[Dynamic Target Bitrate Math] ◄─── Bitrate = (Target MB × 8192) / Duration
│
▼
[FFmpeg WebAssembly Pipeline] ◄─── Local CPU software re-encoding
│
▼
[Instant Local MP4 Download] ◄─── Encoded with ‘+faststart’ web streaming

  1. The Tech Stack

Framework: Next.js 16 (App Router)
Interactive Core: @ffmpeg/ffmpeg and @ffmpeg/util
Styling: Tailwind CSS v4
Hosting:** Vercel (Edge network)

  1. Engineering Challenges & Solutions

A. Eliminating Third-Party CDN Latency
Originally, the app loaded @ffmpeg/core from public CDNs (unpkg.com). This created a single point of failure: privacy extensions and ad-blockers regularly blocked external CDN requests.

The Solution: Self-hosting the .wasm and .js binaries in the /public/ffmpeg/ directory with immutable edge caching:


typescript
await ffmpeg.load({
  coreURL: await toBlobURL("/ffmpeg/ffmpeg-core.js", "text/javascript"),
  wasmURL: await toBlobURL("/ffmpeg/ffmpeg-core.wasm", "application/wasm"),
});

B. Mobile Safari Memory Guard
iOS Safari enforces a strict WebAssembly heap allocation limit (typically 1GB–1.5GB). Attempting to process a 4K 60fps file directly in browser memory causes the tab to crash.
To protect the user experience, we implemented client-side file size guards before allocating memory:

const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
if (isMobile && file.size > 150 * 1024 * 1024) {
  setError("Files over 150MB may exceed mobile browser memory. Please use a desktop browser.");
  return;
}

C. Fast Bilinear Downscaling
4K video has 8.3 million pixels per frame. Using FFmpeg's default bicubic scaler inside single-threaded WebAssembly resulted in long encoding times.
By introducing -sws_flags fast_bilinear and -preset ultrafast, we cut downscaling CPU cycles by 60% to 70% while maintaining crisp 720p HD output for platform limits like:
Discord 8MB Limit
WhatsApp 16MB Limit
Gmail / Outlook 25MB Attachments




Enter fullscreen mode Exit fullscreen mode

원문에서 계속 ↗