Vectorio: SVG'yi Tarayıcıda Component'e Dönüştürmek
Kimsenin Konuşmadığı 5 Dakikalık Vergi
Figma'dan bir icon export ediyorsun. SVG'yi projeye atıyorsun. Ve gerçekten kullanılabilir hale gelene kadar şu dansı yapıyorsun:
xmlns:figma,data-name,data-figma-*çöplerini temizle.id="gradient-1"gibi id'leri yeniden adlandır ki bir sonraki icon'la çakışmasın.- CSS'ten boyutlandırmayı imkânsız hale getiren
width="64",height="64"gibi hardcoded değerleri sök. - Component'e sar,
fillvestroke'u prop'a taşı, JSX için casing'i düzelt (fill-rule→fillRule). - Decorative mi (
aria-hidden), label'lı mı (role="img"+<title>) karar ver.
Hiçbir zaman beş dakikadan uzun sürmüyor. Ama her seferinde yapıyorsun. Ve id rename'i unutup aynı gradient-1 ile iki icon ship edersen, biri sessiz sessiz prod'da yanlış render olmaya başlıyor.
Bu iş tek paste'le bitebilir olsun istedim. Vectorio o.
vectorio.app · github.com/berkinduz/vectorio
Ne Yapıyor
Bir SVG yapıştır (ya da bir klasörü drop et), framework'ünü seç, sana idiomatic ve tree-shakable bir component kodu döndürsün.
Hedefler: React, Vue, Svelte, Solid — opsiyonel TypeScript ve Tailwind çıktısıyla. Her şey tarayıcıda olur. Upload yok, sunucu yok, hesap yok.
Neden Sadece Tarayıcı
Dürüst sebep: SVG temizliği saf bir fonksiyon. Input → output, state yok, korunacak secret yok, rate limit'e takılan API yok. Bunun önüne sunucu koymak feature değil, yük.
Sıfır-backend kararının somut sonuçları:
- Default'ta privacy. Icon'ların makineni terk etmiyor. Henüz yayınlanmamış ürün üzerinde çalışanlar için bu kulağa geldiğinden daha önemli.
- Vercel'de static hosting. Cold start yok, bandwidth dışında maliyet yok.
- URL üzerinden state share'i. Converter konfigürasyonu URL'in kendisine encode oluyor. Veritabanı yok, auth yok, ama bir takım arkadaşın tek tıkla senin tam kurulumunu açıyor.
Uygulama React 19 + Vite 8, vanilla CSS ile. UI library yok — yüzey alanı, bir stylesheet'in Tailwind config'inden kısa kalacağı kadar küçük. (Mockator'da sunucuyu stateless tutmamı sağlayan aynı içgüdü: iş state istemiyorsa, state ship etme.)
Tüm Aracı Doğuran Bug: ID Collision
Aynı sayfaya gradient'lı iki SVG import edip birinin sessizce gri render olmasını izlediysen, tanışıyoruz:
<!-- icon-a.svg -->
<linearGradient id="gradient-1">...</linearGradient>
<rect fill="url(#gradient-1)" />
<!-- icon-b.svg -->
<linearGradient id="gradient-1">...</linearGradient>
<rect fill="url(#gradient-1)" />
İki icon da #gradient-1'e referans veriyor. Browser her iki referansı da hangi <linearGradient>'i önce parse ettiyse ona bağlıyor. İkinci icon gradient'ini kaybediyor.
Vectorio bunu, conversion sırasında her internal id'yi component adıyla namespace'leyerek çözüyor:
<linearGradient id="HomeIcon__gradient-1">...</linearGradient>
<rect fill="url(#HomeIcon__gradient-1)" />
Sıkıcı. Mekanik. Aslında hiçbir zaman senin problemin olmaması gereken cinsten.
Tek Parse'tan Çoklu Framework
İlginç tasarım kararı: SVG'yi tek seferde bir intermediate AST'e parse et, sonra her framework için ayrı emitter yaz. React/Vue/Svelte hazırken Solid'i eklemek yaklaşık bir gün aldı — çoğunlukla soyutlamanın ekmeğini hak ettiği için.
Her emitter kendi kuyrukların ve quirk'leriyle ilgileniyor:
- React: kebab-case → camelCase (
stroke-width→strokeWidth),class→className, props spread. - Vue:
:fillbinding, TS açıksa<script setup>. - Svelte:
{props}shorthand, reaktif size prop'ları. - Solid: React'a benzer, ama runtime'da seni ısıran küçük Solid'e özgü farklarla.
Auto-detected props en gurur duyduğum kısım. Vectorio SVG'yi fill, stroke ve boyutlar için tarıyor, makul defaultlarla bunları component prop'una çıkarıyor — yani çıktı, fonksiyona sarılmış statik markup değil, gerçekten parametre alan bir component.
Batch Mode: Klasörden Yayınlanabilir Pakete
Tek icon'lar ısınma. Asıl kazanç batch mode'da.
Bir SVG klasörü drop et. Vectorio:
- Her dosyayı temizleyip dönüştürüyor.
- Çakışan dosya adlarını otomatik namespace'liyor — iki alt klasördeki
arrow.svg'lar birbirine girmesin diye. index.tsbarrel export'u üretiyor.package.jsonveREADME.mdüretiyor.- Sana bir ZIP veriyor.
Tamamen client-side, JSZip ile. Çıkardığın klasörü monorepo'na at, npm publish çek, icon library'n hazır. Genelde designer-handoff sürecinin sahip olduğu sıkıcı pipeline, tek upload'a sıkıştırılmış.
Üç Mod, Erişilebilirlik
Geç eklenen ama ilk günden olması gereken bir parça. Component içindeki SVG'ler şunlardan biri olabilir:
- Decorative —
aria-hidden="true", semantic ağırlığı yok. - Labeled —
role="img"ve prop'tan gelen bir<title>. - Hidden — sadece
<defs>taşıyan, hiç render edilmemesi gereken sprite'lar.
Vectorio bir kez soruyor, doğru markup'ı emit ediyor. Çoğu icon library "her yerde decorative" default'uyla geliyor ve sessizce accessibility audit'lerden kalıyor. Codegen anında doğru yapmak sıfır maliyet; yüzlerce component'te sonradan düzeltmek bir proje.
Stack, Kısaca
- React 19 + Vite 8 uygulama için.
- Vitest + jsdom parser test'leri, ek olarak gerçek Figma export'larından oluşan fixture klasörüne karşı çalışan smoke check script.
- JSZip client-side packaging için.
- Custom prerender script
vite buildsonrası, marketing yüzeyi için SEO uyumlu statik HTML. - Vercel Analytics, hosting Vercel.
Build pipeline projenin boyutunun gerektirdiğinden biraz daha disiplinli — prerender, smoke check, vitest, lint, typecheck — ama parser'da bir regression user output'unu sessizce bozar, CI'da fark etmek birinin repo'sunda fark etmekten iyi.
Sırada Ne Var
Listedeki birkaç şey, ne kadar istediğime göre yaklaşık sırayla:
- VS Code extension. Bir SVG'ye sağ tıkla, component clipboard'a düşsün.
- CLI. Build-step'te kullanım için
npx vectorio ./icons --out ./components. - Figma plugin. Export adımını tamamen atla.
- Sprite-sheet output. 200 component yerine optimize edilmiş tek SVG ship etmek isteyen takımlar için.
Dene
vectorio.app — bir SVG yapıştır, framework seç. Tamamı MIT lisansı altında açık kaynak: github.com/berkinduz/vectorio.
Parser'ı kıran bir SVG bulursan, dosyayı ekleyerek issue aç. Bunlar en faydalı bug raporları — test suite'indeki her fixture, birinin bozuk export'u olarak başladı.