Browser-based image compression — SSG, i18n, programmatic landing pages & SEO. Built with Vite + React + Tailwind CSS. Deployed on Cloudflare Pages.
Live demo: https://zipo.pics
- SSG (Static Site Generation) — Vite +
prerender.mjsrenders every page to static HTML at build time. Zero server runtime, zero latency. - 9-Language i18n — Self-built lightweight i18n using
useSyncExternalStore+ localStorage. Supports RTL (Farsi), falls back to English. Languages: zh, zh-Hant, en, tr, fr, es, ko, ja, fa. - Programmatic Landing Pages — Define pages as slug tuples; auto-generate routes, sitemap, and hreflang. 55+ pages from a single data structure.
- SEO Built-in — Per-page
<title>,<meta description>, canonical URLs, hreflang alternates,sitemap.xml,robots.txt,llms.txt. - Cloudflare Pages — One-command deploy. Static assets served from edge, zero configuration.
- Zero Dependencies on Server — No database, no backend API, no secrets. 100% client-side.
# Install
npm install
# Dev server (http://localhost:4174)
npm run dev
# Build (SSG → dist/)
npm run build
# Preview production build
npm run previewsrc/
├── main.tsx # Client entry (hydration)
├── App.tsx # Root component (routes by locale+page)
├── entry-server.tsx # SSR entry — renders React to HTML string
├── i18n/
│ └── index.tsx # i18n provider + useSyncExternalStore
└── ...
prerender.mjs # SSG pipeline — renders all (locale, page) combos
scripts/
├── gen-pages.mjs # Generate programmatic landing page slugs
└── indexnow-push.mjs # IndexNow URL submission (Bing/Yandex/Naver)
public/
├── robots.txt
├── _headers # Cloudflare Pages headers (COI/COEP/CORP)
└── sitemap.xml # Generated by prerender
vite build→dist/index.html(template with<div id="app">)vite build --ssr→dist-server/entry-server.js(SSR renderer)prerender.mjsiterates all(locale, page)targets → callsrender()→ writesdist/<locale>/<page>/index.html- Generates
sitemap.xmlwith hreflang alternates +robots.txt
// src/entry-server.tsx
const PAGES = {
'compress-image-to': ['20kb', '50kb', '100kb', '200kb', '500kb'],
'compress-image-for': ['twitter', 'instagram', 'linkedin', 'wordpress', 'web'],
}
// 9 languages × (1 home + 10 pages) = 99 static pagesEach page gets its own canonical URL, hreflang alternates in all 9 languages, and is included in the sitemap.
// Top-level keys must exist in ALL language files, or TypeScript fails.
// This is a design choice — it prevents missing translations at runtime.
const { t } = useI18n()
t('home.title') // → "Free Image Compressor" (en) / "在线图片压缩工具" (zh)# 1. Build
npm run build
# 2. Deploy
npx wrangler pages deploy dist --project-name your-projectOr connect the repo in the Cloudflare Dashboard → Workers & Pages → Create → Pages → Connect to Git.
| Layer | Technology |
|---|---|
| Framework | Vite 6 + React 18 |
| Styling | Tailwind CSS 3 |
| i18n | Self-built (useSyncExternalStore + localStorage) |
| SSG | vite build + prerender.mjs |
| Deploy | Cloudflare Pages (edge, zero config) |
| TypeScript | 5.6 (strict mode) |
MIT © 2026 zipo.pics contributors
zipo.pics — Free browser-based image compression
zipo.pics ·
Sitemap ·
Robots