Nette Assets
Web uygulamalarınızdaki statik dosyaları elle yönetmekten bıktınız mı? Yolları koda gömmeyi, önbellek geçersizleştirmeyle uğraşmayı ya da dosya sürümlemesi için endişelenmeyi unutun. Nette Assets, görsellerle, stil sayfalarıyla, betiklerle ve diğer statik kaynaklarla çalışma biçiminizi dönüştürür.
- Akıllı sürümleme tarayıcıların her zaman en son dosyaları yüklemesini sağlar
- Dosya tiplerinin ve boyutlarının otomatik algılanması
- Sezgisel etiketlerle kusursuz Latte entegrasyonu
- Dosya sistemlerini, CDN'leri ve Vite'ı destekleyen esnek mimari
- En iyi başarım için tembel yükleme
Neden Nette Assets?
Statik dosyalarla çalışmak sıklıkla yinelenen, hataya açık kod anlamına gelir. URL'leri elle kurar, önbellek geçersizleştirme için sürüm parametreleri ekler ve farklı dosya tiplerini farklı biçimde ele alırsınız. Bu, şöyle bir koda yol açar:
<img src="/images/logo.png?v=1699123456" width="200" height="100" alt="Logo">
<link rel="stylesheet" href="/css/style.css?v=2">
Nette Assets ile tüm bu karmaşıklık ortadan kalkar:
{* Her şey otomatik - URL, sürümleme, boyutlar *}
<img n:asset="images/logo.png">
<link n:asset="css/style.css">
{* Ya da yalnızca *}
{asset 'css/style.css'}
Hepsi bu! Kütüphane otomatik olarak:
- Dosyanın değiştirilme zamanına göre sürüm parametreleri ekler
- Görsel boyutlarını algılar ve onları HTML'e ekler
- Her dosya tipi için doğru HTML elemanını üretir
- Hem geliştirme hem üretim ortamlarını ele alır
Kurulum
Nette Assets'i Composer kullanarak kurun:
composer require nette/assets
PHP 8.1 ya da daha yenisini gerektirir ve Nette Framework ile kusursuz çalışır, ama tek başına da kullanılabilir.
İlk Adımlar
Nette Assets sıfır yapılandırmayla, kutudan çıktığı gibi çalışır. Statik dosyalarınızı www/assets/
dizinine koyun ve onları kullanmaya başlayın:
{* Bir görseli otomatik boyutlarla göster *}
{asset 'logo.png'}
{* Sürümlemeyle bir stil sayfası ekle *}
{asset 'style.css'}
{* Bir betik yükle *}
{asset 'app.js'}
Üretilen HTML üzerinde daha fazla denetim için n:asset niteliğini ya da asset() fonksiyonunu
kullanın.
Nasıl Çalışır
Nette Assets, onu güçlü ama kullanımı basit kılan üç temel kavram üzerine kurulmuştur:
Varlıklar – Akıllanmış Dosyalarınız
Bir varlık (asset), uygulamanızdaki herhangi bir statik dosyayı temsil eder. Her dosya, yararlı salt okunur özelliklere sahip bir nesneye dönüşür:
$image = $assets->getAsset('photo.jpg');
echo $image->url; // '/assets/photo.jpg?v=1699123456'
echo $image->file; // '/var/www/assets/photo.jpg' (yerel yol ya da null)
echo $image->width; // 1920
echo $image->height; // 1080
echo $image->mimeType; // 'image/jpeg'
Farklı dosya tipleri farklı özellikler sunar:
- Görseller: genişlik, yükseklik, alternatif metin, tembel yükleme
- Betikler: modül tipi, bütünlük hash'leri, crossorigin
- Stil sayfaları: medya sorguları, bütünlük
- Ses/Video: süre, boyutlar (yalnızca video)
- Yazı tipleri: CORS ile doğru önyükleme
Kütüphane dosya tiplerini otomatik algılar ve uygun varlık sınıfını oluşturur.
Mapper'lar – Dosyaların Geldiği Yer
Bir mapper, dosyaları nasıl bulacağını ve onlar için URL'leri nasıl oluşturacağını bilir. Farklı amaçlar
için birden çok mapper'ınız olabilir: yerel dosyalar, CDN, bulut depolama ya da derleme araçları (her birinin bir adı
vardır). Yerleşik FilesystemMapper yerel dosyaları ele alırken, ViteMapper modern derleme
araçlarıyla bütünleşir.
Mapper'lar yapılandırmada tanımlanır.
Registry – Ana Arayüzünüz
Registry, tüm mapper'ları yönetir ve ana API'yi sunar:
// Registry'yi servisinize enjekte edin
public function __construct(
private Nette\Assets\Registry $assets
) {}
// Farklı mapper'lardan varlık alın
$logo = $this->assets->getAsset('images:logo.png'); // 'images' mapper'ı
$app = $this->assets->getAsset('app:main.js'); // 'app' mapper'ı
$style = $this->assets->getAsset('style.css'); // varsayılan mapper'ı kullanır
Registry doğru mapper'ı otomatik seçer ve başarım için sonuçları önbelleğe alır.
PHP'de Varlıklarla Çalışma
Registry, varlıkları almak için iki metot sunar:
// Dosya yoksa Nette\Assets\AssetNotFoundException fırlatır
$logo = $assets->getAsset('logo.png');
// Dosya yoksa null döndürür
$banner = $assets->tryGetAsset('banner.jpg');
if ($banner) {
echo $banner->url;
}
Mapper Belirtme
Hangi mapper'ın kullanılacağını açıkça seçebilirsiniz:
// Varsayılan mapper'ı kullan
$file = $assets->getAsset('document.pdf');
// Belirli bir mapper'ı önekle kullan
$image = $assets->getAsset('images:photo.jpg');
// Belirli bir mapper'ı dizi sözdizimiyle kullan
$script = $assets->getAsset(['scripts', 'app.js']);
Varlık Özellikleri ve Tipleri
Her varlık tipi, ilgili salt okunur özellikleri sunar:
// Görsel özellikleri
$image = $assets->getAsset('photo.jpg');
echo $image->width; // 1920
echo $image->height; // 1080
echo $image->mimeType; // 'image/jpeg'
// Betik özellikleri
$script = $assets->getAsset('app.js');
echo $script->type; // null (Vite giriş noktaları için 'module')
// Ses özellikleri
$audio = $assets->getAsset('song.mp3');
echo $audio->duration; // saniye cinsinden süre
// Tüm varlıklar dizeye dönüştürülebilir (URL döndürür)
$url = (string) $assets->getAsset('document.pdf');
Boyutlar ya da süre gibi özellikler yalnızca erişildiğinde tembel yüklenir; bu da kütüphaneyi hızlı tutar.
Kesin statik çözümleme için nette/phpstan-rules uzantısını kurun. PHPStan o zaman her
varlığın somut tipini bilir, dolayısıyla getAsset('photo.jpg') çağrısı ImageAsset olarak
anlaşılır ve ->width erişimi hata vermez.
Latte Şablonlarında Varlıkları Kullanma
Nette Assets, etiketler ve fonksiyonlarla sezgisel Latte entegrasyonu sunar.
{asset}
{asset} etiketi tam HTML elemanları render eder:
{* Render eder: <img src="/assets/hero.jpg?v=123" width="1920" height="1080"> *}
{asset 'hero.jpg'}
{* Render eder: <script src="/assets/app.js?v=456"></script> *}
{asset 'app.js'}
{* Render eder: <link rel="stylesheet" href="/assets/style.css?v=789"> *}
{asset 'style.css'}
Etiket otomatik olarak:
- Varlık tipini algılar ve uygun HTML'i üretir
- Önbellek geçersizleştirme için sürümleme ekler
- Görseller için boyutları ekler
- Doğru nitelikleri ayarlar (type, media vb.)
HTML niteliklerinin içinde ya da <style> ve <script> elemanlarının içinde
kullanıldığında yalnızca URL'yi çıktılar:
<div style="background-image: url({asset 'bg.jpg'})">
<img srcset="{asset 'logo@2x.png'} 2x">
n:asset
HTML nitelikleri üzerinde tam denetim için:
{* n:asset niteliği src, boyutlar vb. alanları doldurur *}
<img n:asset="product.jpg" alt="Product" class="rounded">
{* İlgili her elemanla çalışır *}
<script n:asset="analytics.js" defer></script>
<link n:asset="print.css" media="print">
<audio n:asset="podcast.mp3" controls></audio>
Değişkenleri ve mapper'ları kullanın:
{* Değişkenler doğal biçimde çalışır *}
<img n:asset="$product->image">
{* Mapper'ı süslü parantezlerle belirtin *}
<img n:asset="images:{$product->image}">
{* Mapper'ı dizi yazımıyla belirtin *}
<img n:asset="[images, $product->image]">
n:asset ayrıca <a> elemanında da çalışır ve orada href alanını doldurur;
<link> elemanında ise bir preload ipucu oluşturur:
<a n:asset="hero.jpg">Görseli indir</a>
<a> ve <link> çeşitlerinin yalnızca render edilebilir varlıklar (bir görsel, bir
betik vb.) için çalıştığını, bir PDF gibi GenericAsset için asla çalışmadığını unutmayın.
Görseller için yalnızca width (ya da yalnızca height) ayarlamak yeterlidir; diğer boyut en-boy
oranını koruyacak biçimde otomatik hesaplanır:
{* height, en-boy oranından tamamlanır *}
<img n:asset="product.jpg" width="200">
asset()
En üst düzey esneklik için asset() fonksiyonunu kullanın:
{var $logo = asset('logo.png')}
<img src={$logo} width={$logo->width} height={$logo->height}>
{* Ya da doğrudan *}
<img src={asset('logo.png')} alt="Logo">
İsteğe Bağlı Varlıklar
Eksik varlıkları {asset?}, n:asset? ve tryAsset() ile zarif biçimde ele alın:
{* İsteğe bağlı etiket - varlık yoksa hiçbir şey render etmez *}
{asset? 'optional-banner.jpg'}
{* İsteğe bağlı nitelik - varlık yoksa atlar *}
<img n:asset?="user-avatar.jpg" alt="Avatar" class="avatar">
{* Yedekle birlikte *}
{var $avatar = tryAsset('user-avatar.jpg') ?? asset('default-avatar.jpg')}
<img n:asset=$avatar alt="Avatar">
{preload}
Sayfa yükleme başarımını iyileştirin:
{* <head> bölümünüzde *}
{preload 'critical.css'}
{preload 'important-font.woff2'}
{preload 'hero-image.jpg'}
Uygun preload bağlantıları üretir:
<link rel="preload" href="/assets/critical.css?v=123" as="style">
<link rel="preload" href="/assets/important-font.woff2?v=456" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/assets/hero-image.jpg?v=789" as="image" type="image/jpeg">
Yanıtınız nonce içeren bir Content-Security-Policy başlığı ayarladığında,
Nette üretilen her <script>, <link> ve <style> elemanına eşleşen
nonce niteliğini otomatik ekler; böylece onlar tarayıcının güvenlik ilkesince engellenmez.
Gelişmiş Özellikler
Uzantı Otomatik Algılama
Birden çok biçimi otomatik ele alın:
assets:
mapping:
images:
path: img
extension: [webp, jpg, png] # Sırayla dene
Artık uzantı olmadan isteyebilirsiniz:
{* logo.webp, logo.jpg ya da logo.png dosyasını otomatik bulur *}
{asset 'images:logo'}
Modern biçimlerle aşamalı iyileştirme için mükemmel.
Akıllı Sürümleme
Dosyalar, değiştirilme zamanlarına göre otomatik sürümlenir:
{asset 'style.css'}
{* Çıktı: <link rel="stylesheet" href="/assets/style.css?v=1699123456"> *}
Dosyayı güncellediğinizde zaman damgası değişir ve tarayıcı önbelleğinin tazelenmesi zorlanır.
Sürümlemeyi varlık başına denetleyin:
// Belirli bir varlık için sürümlemeyi kapat
$asset = $assets->getAsset('style.css', ['version' => false]);
{* Latte'de *}
{asset 'style.css', version: false}
Aynı reference, key: value sözdizimi, seçenekleri n:asset ve {preload} etiketlerine
de aktarır:
<img n:asset="photo.jpg, version: false">
{preload 'style.css', version: false}
Yazı Tipi Varlıkları
Yazı tipleri, doğru CORS ile özel bir muamele görür:
{* crossorigin ile doğru preload *}
{preload 'fonts:OpenSans-Regular.woff2'}
{* CSS'te kullanım *}
<style>
@font-face {
font-family: 'Open Sans';
src: url('{asset 'fonts:OpenSans-Regular.woff2'}') format('woff2');
font-display: swap;
}
</style>
Özel Mapper'lar
Bulut depolama ya da dinamik üretim gibi özel gereksinimler için özel mapper'lar oluşturun:
use Nette\Assets\Mapper;
use Nette\Assets\Asset;
use Nette\Assets\Helpers;
class CloudStorageMapper implements Mapper
{
public function __construct(
private CloudClient $client,
private string $bucket,
) {}
public function getAsset(string $reference, array $options = []): Asset
{
if (!$this->client->exists($this->bucket, $reference)) {
throw new Nette\Assets\AssetNotFoundException("Asset '$reference' not found");
}
$url = $this->client->getPublicUrl($this->bucket, $reference);
return Helpers::createAssetFromUrl($url);
}
}
Yapılandırmada kaydedin:
assets:
mapping:
cloud: CloudStorageMapper(@cloudClient, 'my-bucket')
Diğer mapper'lar gibi kullanın:
{asset 'cloud:user-uploads/photo.jpg'}
Helpers::createAssetFromUrl() metodu, dosya uzantısına göre doğru varlık tipini otomatik oluşturur.
Nette\Assets\HtmlRenderable arayüzünü gerçekleştiren varlık tipleri (görseller, betikler, stiller vb.)
{asset} tarafından tam bir HTML elemanı olarak render edilebilir. Diğer dosya tipleri bir
GenericAsset olur (örneğin bir PDF); bu HTML elemanı olarak render edilemez, ama yine de bir URL (ve başka
üstveri) sunar. Böyle bir varlığı HTML elemanı olarak render etmeye çalışmak Nette\InvalidArgumentException
fırlatır; URL'sini yine de bir niteliğin içinde kullanabilirsiniz.