Mengubah logo raster (PNG/JPEG) menjadi aset vektor teranimasi secara manual memperlambat siklus rilis dan rawan inkonsistensi rendering. Integrasi konversi langsung ke pipeline Continuous Integration (CI) memastikan setiap aset raster yang masuk ke repositori otomatis diproses menjadi SVG ringan, disuntikkan keyframe animasi CSS, dan divalidasi atribut DOM-nya sebelum dipublikasikan.
Arsitektur Pipeline Konversi dan QA
Pipeline ini menggunakan model pemrosesan bertahap yang menggabungkan Python (untuk tracing vektor berbasis algoritma Potrace atau logika serupa pixel2motion) dan Node.js (untuk optimasi SVGO serta pengujian DOM). Alur kerja terdiri dari empat tahap:
- Vector Tracing: Mengonversi bitmap monokrom atau multichannel menjadi path vektor berformat SVG dasar.
- Animation Injection & Optimization: Menyematkan keyframe CSS (stroke-dasharray, stroke-dashoffset, opacity) ke dalam elemen SVG, kemudian mengompresi payload via SVGO.
- Automated QA Assertion: Memverifikasi ukuran file, keberadaan atribut visual pada path, dan durasi animasi CSS secara headless.
- Artifact Generation: Menghasilkan HTML demo preview visual untuk inspeksi manual oleh tim desain jika build gagal atau sukses.
Implementasi Skrip Validasi QA Headless
Pengujian otomatis memastikan vektor hasil konversi tidak menghasilkan path kosong atau ukuran payload yang membengkak akibat densitas node yang berlebihan. Buat skrip Node.js dengan jsdom untuk menjalankan verifikasi terprogram:
// scripts/validate-svg.mjs
import fs from 'node:fs';
import { JSDOM } from 'jsdom';
const FILE_PATH = process.argv[2];
const MAX_SIZE_KB = 50;
const MIN_PATHS = 1;
if (!FILE_PATH || !fs.existsSync(FILE_PATH)) {
console.error(`Error: File tidak ditemukan di lintasan ${FILE_PATH}`);
process.exit(1);
}
// 1. Validasi Ukuran Payload
const stats = fs.statSync(FILE_PATH);
const fileSizeKB = stats.size / 1024;
if (fileSizeKB > MAX_SIZE_KB) {
console.error(`QA Gagal: Ukuran SVG (${fileSizeKB.toFixed(2)} KB) melampaui batas (${MAX_SIZE_KB} KB)`);
process.exit(1);
}
// 2. Validasi Struktur DOM dan Keyframe CSS
const content = fs.readFileSync(FILE_PATH, 'utf-8');
const dom = new JSDOM(content, { contentType: 'image/svg+xml' });
const document = dom.window.document;
const paths = document.querySelectorAll('path');
if (paths.length < MIN_PATHS) {
console.error(`QA Gagal: Tidak ada path vektor terdeteksi.`);
process.exit(1);
}
const styleTag = document.querySelector('style');
if (!styleTag || !styleTag.textContent.includes('@keyframes')) {
console.error('QA Gagal: Tag style tidak memuat definisi @keyframes animasi.');
process.exit(1);
}
// Verifikasi atribut path untuk animasi stroke
let validAnimatedPaths = 0;
paths.forEach((path) => {
const d = path.getAttribute('d');
if (d && d.trim().length > 0) {
validAnimatedPaths++;
}
});
if (validAnimatedPaths === 0) {
console.error('QA Gagal: Seluruh path memiliki atribut data d yang kosong.');
process.exit(1);
}
console.log(`QA Sukses: ${FILE_PATH} lolos validasi (${fileSizeKB.toFixed(2)} KB, ${validAnimatedPaths} path).`);
process.exit(0);Konfigurasi GitHub Actions Workflow
Workflow berikut menjalankan pemrosesan saat ada perubahan file di direktori assets/raw/**, memanfaatkan native cache untuk dependensi pip dan npm, lalu menyimpan HTML demo sebagai artefak build.
# .github/workflows/asset-pipeline.yml
name: Asset Conversion & QA Pipeline
on:
push:
paths:
- 'assets/raw/**'
pull_request:
paths:
- 'assets/raw/**'
jobs:
convert-and-validate:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install System Dependencies
run: |
sudo apt-get update
sudo apt-get install -y potrace
- name: Install Project Dependencies
run: |
pip install -r requirements.txt
npm ci
- name: Convert Raster to Vector Animation
run: |
# Menjalankan konverter internal berbasis tracing dan CSS injection
python scripts/convert_to_animated_svg.py assets/raw/logo.png assets/dist/logo.svg
- name: Optimize Vector with SVGO
run: |
npx svgo assets/dist/logo.svg --config svgo.config.mjs -o assets/dist/logo.min.svg
- name: Run QA Validations
run: |
node scripts/validate-svg.mjs assets/dist/logo.min.svg
- name: Generate HTML Preview
run: |
cat <<EOF > assets/dist/index.html
<!DOCTYPE html>
<html>
<head><title>Preview Animasi SVG</title></head>
<body style="background:#121212;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;">
<img src="logo.min.svg" width="400" />
</body>
</html>
EOF
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: animated-asset-preview
path: assets/dist/
retention-days: 7Strategi Optimasi SVGO dan Caching Artefak
Secara default, SVGO menghapus deklarasi style inline atau atribut yang dianggap redundan. Pastikan konfigurasi svgo.config.mjs mempertahankan tag animasi:
// svgo.config.mjs
export default {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
cleanupIds: false,
inlineStyles: false,
},
},
},
],
};Manajemen Caching CI
Tracing gambar raster dan kompilasi modul Node.js adalah bottleneck utama durasi runner. Konfigurasi cache: 'npm' pada actions/setup-node serta cache: 'pip' pada actions/setup-python memanfaatkan hash dari package-lock.json dan requirements.txt. Mekanisme ini memangkas waktu build hingga 40-60% karena runner melewatkan fase download dependensi pada run berulang.
Trade-off dan Limitasi Teknis
- Noise dan Path Complexity: Gambar raster bergradien tinggi atau foto realistis menghasilkan path koordinat yang terlalu padat, membuat ukuran SVG justru berkali-kali lipat lebih besar dibanding WebP atau AVIF. Batasi pipeline ini khusus untuk icon, mark, dan logo berbasis flat vector.
- Headless DOM Limitations:
jsdomtidak mengkalkulasi rendering visual nyata (layout reflow atau paint). Pemeriksaan hanya membuktikan keberadaan sintaks CSS dan atribut, bukan kebenaran tampilan visual. Jika diperlukan visual regression testing tingkat lanjut, gunakan headless browser engine seperti Playwright.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!