Mengoptimalkan pengiriman aset statis di FrankenPHP: kompresi on-the-fly dengan encode zstd br gzip, menyajikan file yang sudah dikompresi lewat precompressed, header Cache-Control & ETag untuk browser caching, dan memisahkan rute aset agar tidak membebani PHP.

Setelah dua episode terakhir fokus pada framework (Laravel dan Symfony), episode ini membahas lapisan yang menentukan kesan kecepatan pertama pengguna: pengiriman aset statis. CSS, JavaScript, gambar, dan font biasanya menyumbang mayoritas byte yang ditransfer — dan di sinilah keunggulan FrankenPHP/Caddy terasa: kompresi modern, HTTP caching, dan efisiensi file server, semuanya bawaan.
Mengapa penting? php_server secara default sudah menyalakan file server, tetapi file server yang "jalan apa adanya" tanpa kompresi dan header cache akan membuat halaman terasa lambat walau PHP-nya secepat kilat. Pengoptimalan yang kita lakukan di episode ini sering kali memberi peningkatan skor performa terbesar dengan usaha terkecil.
encode zstd br gzipCaddy mendukung tiga algoritma kompresi modern sekaligus. Prioritasnya penting:
localhost {
encode zstd br gzip
root * public/
php_server
}Urutan di atas berarti: jika browser mendukung Zstandard (zstd), kirim zstd; jika tidak, turun ke Brotli (br); terakhir gzip sebagai jaring pengaman universal. Zstd dan Brotli menghasilkan rasio kompresi lebih baik dengan kecepatan lebih tinggi daripada gzip untuk aset teks.
Tip
Posisi encode di Caddyfile menentukan apa yang ikut dikompresi. Letakkan di awal site block agar semua response (termasuk dari reverse_proxy) terkompresi. Untuk aset yang sudah dikompresi (gambar JPEG/PNG, video), kompresi tambahan hanya buang CPU.
precompressedKompresi on-the-fly menghabiskan CPU per request. Untuk produksi dengan trafik tinggi, kompresi file sekali saat build lalu biarkan Caddy menyajikan versi terkompresi tanpa kerja tambahan. Symfony AssetMapper punya dukungan built-in:
php bin/console asset-map:compileIni menghasilkan app.css.zst, app.css.br, dll. Lalu Caddyfile:
localhost {
@assets path /assets/*
file_server @assets {
precompressed zstd br gzip
}
root * public/
php_server {
try_files {path} index.php
}
}precompressed membuat Caddy memeriksa keberadaan app.css.zst/app.css.br/app.css.gz saat ada request app.css — dan mengirim versi terkompresi tanpa mengompresi apa pun saat runtime. Browser menerima Content-Encoding yang tepat sesuai kemampuan negosiasinya.
php_server secara default memeriksa apakah request adalah file statis sebelum meneruskan ke PHP. Untuk aplikasi dengan front controller tunggal (Laravel/Symfony), kita bisa lebih agresif: aset hanya hidup di /assets, sisanya langsung ke PHP. Ini menghindari pencarian filesystem yang sia-sia di hot path.
localhost {
route {
@assets path /assets/*
file_server @assets {
root public/
precompressed zstd br gzip
}
rewrite index.php
php {
root public/
}
}
}/assets/* → file server dengan precompression.index.php langsung, tanpa cek file.php (bukan php_server) karena di sini kita tidak butuh file server bawaan — aset sudah ditangani sendiri.Browser caching menentukan berapa banyak request aset yang benar-benar keluar dari server. Header Cache-Control diatur via directive header:
localhost {
@assets path /assets/*
header @assets {
Cache-Control "public, max-age=31536000, immutable"
}
file_server @assets
root * public/
php_server
}max-age=31536000 = satu tahun. Aman untuk aset dengan fingerprint nama file (misal app-abc123.css).immutable memberi tahu browser bahwa isi tidak akan berubah — cegah revalidation yang tidak perlu.no-cache atau cache pendek.Caddy secara default menghitung ETag (fingerprint file) dan melayani If-None-Match — browser mengirim request sangat ringan dan menerima 304 Not Modified jika file tak berubah. Ini bekerja otomatis di file_server, jadi tidak perlu konfigurasi tambahan — hanya perlu dipahami saat kalian melihat 304 di log.
encode pada mereka membuang CPU dan bisa malah memperbesar ukuran. Batasi kompresi ke tipe teks dengan matcher.precompressed saat pindah ke CDN: file .zst/.br di-root asset tidak akan dikirim dengan benar jika CDN tidak tahu header Content-Encoding. Pastikan konfigurasi CDN meneruskan header tersebut.file_server off pada php_server: jika kalian mematikan file server, pastikan aset dilayani jalur lain — jika tidak, semua aset 404.Pada episode 8 ini, kalian telah mengoptimalkan pengiriman aset statis.
Inti yang harus dibawa pulang:
encode zstd br gzip — kompresi modern dengan prioritas yang benar.precompressed — sajikan file hasil build tanpa CPU runtime./assets/* agar PHP tidak diganggu pencarian filesystem.Cache-Control + ETag untuk memaksimalkan browser caching.Di episode 9 selanjutnya kita melebarkan horizon: reverse proxy dan load balancing — meneruskan request ke API, microservices, atau backend lain, lengkap dengan health check, load balancing policies, dan trusted_proxies. Sampai jumpa di episode 9!