Stop Uploading Your Files: How I Built a 100% Client-Side Image Converter with React & Vite

Published: (January 14, 2026 at 09:46 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

I got tired of Googling “JPG to PNG” and landing on sketchy websites that demand I upload my personal documents (ID scans, contracts) to a random server just to change a file format.
So, I decided to build my own.

The goal was simple: Zero Server Uploads. I wanted a tool that runs entirely in the browser memory, processes files instantly without lag, and handles bulk conversion without crashing the UI.

The Stack

  • React – UI rendering
  • Vite 6 – fast development server & bundler
  • Zustand – lightweight state management

The Challenge: The “Serverless” Engine

To keep everything client‑side I leveraged the browser’s native Canvas API, but in a non‑traditional way. The architecture acts as a pipeline:

  1. Ingestion – Instead of the old, slow FileReader (which converts images to massive Base64 strings), I switched to createImageBitmap. This decodes the image data directly in the browser’s GPU memory, making it near‑instant.
  2. The “Invisible” Canvas – I programmatically create a <canvas> element that never touches the DOM. It sizes itself to match the image, “paints” the bitmap data onto itself, and then sits in memory.
  3. Extraction – I use the canvas’s ability to export blobs to specific MIME types (e.g., image/png or image/webp). Essentially, I ask the browser to “take a photo” of the canvas in a different format.

Result: A conversion pipeline that handles 5 MB images in milliseconds, with zero network latency.

The Performance Trap: Infinite Loops

I chose Zustand for state management because it’s lightweight, but I initially made a rookie mistake: I hooked my main component to the entire state object.

Every time a single image finished converting, the state updated. Because I was subscribed to the whole object, React saw a new object reference and re‑rendered the entire list. With 50 images updating status one by one, this caused a cascade of re‑renders that looked like a memory leak.

Fix

Refactor the state logic to use atomic selectors. By forcing components to listen only to the specific boolean or array they need, the UI went from “stuttery” to ~60 fps smooth, even during heavy batch processing.

The Business Pivot: AdSense vs. Reality

My initial plan was Google AdSense. I quickly learned that AdSense hates “Single Page Tools.” They flag them as “Low Value Content” because there are no 2,000‑word articles to crawl. Plus, putting Google trackers on a “Privacy” tool felt hypocritical.

I realized that my users aren’t looking for random shoes or credit cards; they are looking for Data Safety.

Pivot

A direct affiliate model. I removed placeholder ad slots and designed custom “Native Cards” that promote privacy‑focused tools (VPNs, password managers). This aligns the revenue model with the product’s mission and feels less like an ad and more like a tech‑stack recommendation.

The Result

  • Supports the modern web trinity: JPG, PNG, WebP
  • Handles vector SVG files perfectly
  • Features a “Holy Grail” symmetrical layout that balances utility with monetization without cluttering the workspace
  • Keeps its promise: you can load the page, disconnect your Wi‑Fi, and convert confidential documents all day long. Nothing ever leaves your machine.

Live demo: Secure Converter
Source code: GitHub Repo

Back to Blog

Related posts

Read more »