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.

Devamını Okuyun

versiyon: 1.x