Nette Assets

Sind Sie es leid, statische Dateien in Ihren Webanwendungen manuell zu verwalten? Vergessen Sie das Hardcodieren von Pfaden, die Cache-Invalidierung oder die Sorge um die Dateiversionierung. Nette Assets verändert die Art und Weise, wie Sie mit Bildern, Stylesheets, Skripten und anderen statischen Ressourcen arbeiten.

  • Intelligente Versionierung stellt sicher, dass Browser immer die neuesten Dateien laden
  • Automatische Erkennung von Dateitypen und Dimensionen
  • Nahtlose Latte-Integration mit intuitiven Tags
  • Flexible Architektur, die Dateisysteme, CDNs und Vite unterstützt
  • Lazy Loading für optimale Leistung

Warum Nette Assets?

Die Arbeit mit statischen Dateien bedeutet oft sich wiederholenden, fehleranfälligen Code. Sie konstruieren URLs manuell, fügen Versionsparameter zur Cache-Busting hinzu und behandeln verschiedene Dateitypen unterschiedlich. Dies führt zu Code wie:

<img src="/images/logo.png?v=1699123456" width="200" height="100" alt="Logo">
<link rel="stylesheet" href="/css/style.css?v=2">

Mit Nette Assets verschwindet all diese Komplexität:

{* Alles automatisiert - URL, Versionierung, Dimensionen *}
<img n:asset="images/logo.png">
<link n:asset="css/style.css">

{* Oder einfach *}
{asset 'css/style.css'}

Das war's! Die Bibliothek erledigt automatisch:

  • Fügt Versionsparameter basierend auf der Dateimodifikationszeit hinzu
  • Erkennt Bilddimensionen und fügt sie in das HTML ein
  • Generiert das korrekte HTML-Element für jeden Dateityp
  • Handhabt sowohl Entwicklungs- als auch Produktionsumgebungen

Installation

Installieren Sie Nette Assets mit Composer:

composer require nette/assets

Es erfordert PHP 8.1 oder höher und funktioniert perfekt mit dem Nette Framework, kann aber auch eigenständig verwendet werden.

Erste Schritte

Nette Assets funktioniert sofort und ohne Konfiguration. Legen Sie Ihre statischen Dateien im Verzeichnis www/assets/ ab und beginnen Sie mit der Verwendung:

{* Zeigt ein Bild mit automatischen Dimensionen an *}
{asset 'logo.png'}

{* Fügt ein Stylesheet mit Versionierung ein *}
{asset 'style.css'}

{* Lädt ein JavaScript-Modul *}
{asset 'app.js'}

Für mehr Kontrolle über das generierte HTML verwenden Sie das Attribut n:asset oder die Funktion asset().

Wie es funktioniert

Nette Assets basiert auf drei Kernkonzepten, die es leistungsstark und dennoch einfach zu bedienen machen:

Assets – Ihre Dateien intelligent gemacht

Ein Asset repräsentiert jede statische Datei in Ihrer Anwendung. Jede Datei wird zu einem Objekt mit nützlichen schreibgeschützten Eigenschaften:

$image = $assets->getAsset('photo.jpg');
echo $image->url;      // '/assets/photo.jpg?v=1699123456'
echo $image->width;    // 1920
echo $image->height;   // 1080
echo $image->mimeType; // 'image/jpeg'

Verschiedene Dateitypen bieten unterschiedliche Eigenschaften:

  • Bilder: Breite, Höhe, Alternativtext, Lazy Loading
  • Skripte: Modultyp, Integritäts-Hashes, Cross-Origin
  • Stylesheets: Media Queries, Integrität
  • Audio/Video: Dauer, Dimensionen
  • Schriftarten: korrektes Preloading mit CORS

Die Bibliothek erkennt Dateitypen automatisch und erstellt die entsprechende Asset-Klasse.

Mapper – Woher Dateien kommen

Ein Mapper weiß, wie Dateien gefunden und URLs für sie erstellt werden. Sie können mehrere Mapper für verschiedene Zwecke haben – lokale Dateien, CDN, Cloud-Speicher oder Build-Tools (jeder von ihnen hat einen Namen). Der eingebaute FilesystemMapper verarbeitet lokale Dateien, während ViteMapper sich in moderne Build-Tools integriert.

Mapper werden in der Konfiguration definiert.

Registry – Ihre Hauptschnittstelle

Die Registry verwaltet alle Mapper und stellt die Haupt-API bereit:

// Injizieren Sie die Registry in Ihren Dienst
public function __construct(
	private Nette\Assets\Registry $assets
) {}

// Assets von verschiedenen Mappern abrufen
$logo = $this->assets->getAsset('images:logo.png'); // 'image' mapper
$app = $this->assets->getAsset('app:main.js'); // 'app' mapper
$style = $this->assets->getAsset('style.css'); // verwendet den Standard-Mapper

Die Registry wählt automatisch den richtigen Mapper aus und speichert die Ergebnisse zur Leistungsverbesserung im Cache.

Arbeiten mit Assets in PHP

Die Registry bietet zwei Methoden zum Abrufen von Assets:

// Wirft Nette\Assets\AssetNotFoundException, wenn die Datei nicht existiert
$logo = $assets->getAsset('logo.png');

// Gibt null zurück, wenn die Datei nicht existiert
$banner = $assets->tryGetAsset('banner.jpg');
if ($banner) {
	echo $banner->url;
}

Mapper angeben

Sie können explizit auswählen, welchen Mapper Sie verwenden möchten:

// Standard-Mapper verwenden
$file = $assets->getAsset('document.pdf');

// Spezifischen Mapper mit Präfix verwenden
$image = $assets->getAsset('images:photo.jpg');

// Spezifischen Mapper mit Array-Syntax verwenden
$script = $assets->getAsset(['scripts', 'app.js']);

Asset-Eigenschaften und -Typen

Jeder Asset-Typ bietet relevante schreibgeschützte Eigenschaften:

// Bildeigenschaften
$image = $assets->getAsset('photo.jpg');
echo $image->width;     // 1920
echo $image->height;    // 1080
echo $image->mimeType;  // 'image/jpeg'

// Skript-Eigenschaften
$script = $assets->getAsset('app.js');
echo $script->type;     // 'module' or null

// Audio-Eigenschaften
$audio = $assets->getAsset('song.mp3');
echo $audio->duration;  // duration in seconds

// Alle Assets können in einen String umgewandelt werden (gibt URL zurück)
$url = (string) $assets->getAsset('document.pdf');

Eigenschaften wie Dimensionen oder Dauer werden nur bei Zugriff verzögert geladen, um die Bibliothek schnell zu halten.

Verwenden von Assets in Latte-Templates

Nette Assets bietet intuitive Latte-Integration mit Tags und Funktionen.

{asset}

Der {asset}-Tag rendert vollständige HTML-Elemente:

{* Rendert: <img src="/assets/hero.jpg?v=123" width="1920" height="1080"> *}
{asset 'hero.jpg'}

{* Rendert: <script src="/assets/app.js?v=456" type="module"></script> *}
{asset 'app.js'}

{* Rendert: <link rel="stylesheet" href="/assets/style.css?v=789"> *}
{asset 'style.css'}

Der Tag erledigt automatisch:

  • Erkennt den Asset-Typ und generiert das passende HTML
  • Fügt Versionierung für Cache-Busting hinzu
  • Fügt Dimensionen für Bilder hinzu
  • Setzt korrekte Attribute (Typ, Medien usw.)

Bei Verwendung innerhalb von HTML-Attributen gibt es nur die URL aus:

<div style="background-image: url({asset 'bg.jpg'})">
<img srcset="{asset 'logo@2x.png'} 2x">

n:asset

Für die volle Kontrolle über HTML-Attribute:

{* Das n:asset Attribut füllt src, Dimensionen usw. aus. *}
<img n:asset="product.jpg" alt="Product" class="rounded">

{* Funktioniert mit jedem relevanten Element *}
<script n:asset="analytics.js" defer></script>
<link n:asset="print.css" media="print">
<audio n:asset="podcast.mp3" controls></audio>

Verwenden Sie Variablen und Mapper:

{* Variablen funktionieren natürlich *}
<img n:asset="$product->image">

{* Mapper mit geschweiften Klammern angeben *}
<img n:asset="images:{$product->image}">

{* Mapper mit Array-Notation angeben *}
<img n:asset="[images, $product->image]">

asset()

Für maximale Flexibilität verwenden Sie die Funktion asset():

{var $logo = asset('logo.png')}
<img src={$logo} width={$logo->width} height={$logo->height}>

{* Oder direkt *}
<img src={asset('logo.png')} alt="Logo">

Optionale Assets

Behandeln Sie fehlende Assets elegant mit {asset?}, n:asset? und tryAsset():

{* Optionaler Tag - rendert nichts, wenn Asset fehlt *}
{asset? 'optional-banner.jpg'}

{* Optionales Attribut - überspringt, wenn Asset fehlt *}
<img n:asset?="user-avatar.jpg" alt="Avatar" class="avatar">

{* Mit Fallback *}
{var $avatar = tryAsset('user-avatar.jpg') ?? asset('default-avatar.jpg')}
<img n:asset=$avatar alt="Avatar">

{preload}

Verbessern Sie die Seitenladeleistung:

{* Im <head>-Bereich *}
{preload 'critical.css'}
{preload 'important-font.woff2'}
{preload 'hero-image.jpg'}

Generiert entsprechende Preload-Links:

<link rel="preload" href="/assets/critical.css?v=123" as="style">
<link rel="preload" href="/assets/important-font.woff2" as="font" crossorigin>
<link rel="preload" href="/assets/hero-image.jpg" as="image">

Erweiterte Funktionen

Erweiterungs-Automatik-Erkennung

Verarbeitet mehrere Formate automatisch:

assets:
	mapping:
		images:
			path: img
			extension: [webp, jpg, png]  # In dieser Reihenfolge versuchen

Jetzt können Sie ohne Erweiterung anfordern:

{* Findet logo.webp, logo.jpg oder logo.png automatisch *}
{asset 'images:logo'}

Perfekt für progressive Verbesserung mit modernen Formaten.

Intelligente Versionierung

Dateien werden automatisch basierend auf der Änderungszeit versioniert:

{asset 'style.css'}
{* Ausgabe: <link rel="stylesheet" href="/assets/style.css?v=1699123456"> *}

Wenn Sie die Datei aktualisieren, ändert sich der Zeitstempel, was eine Aktualisierung des Browser-Caches erzwingt.

Steuern Sie die Versionierung pro Asset:

// Versionierung für bestimmtes Asset deaktivieren
$asset = $assets->getAsset('style.css', ['version' => false]);

// In Latte
{asset 'style.css', version: false}

Schriftarten-Assets

Schriftarten erhalten eine spezielle Behandlung mit korrektem CORS:

{* Korrektes Preload mit Crossorigin *}
{preload 'fonts:OpenSans-Regular.woff2'}

{* Verwendung in CSS *}
<style>
@font-face {
	font-family: 'Open Sans';
	src: url('{asset 'fonts:OpenSans-Regular.woff2'}') format('woff2');
	font-display: swap;
}
</style>

Benutzerdefinierte Mapper

Erstellen Sie benutzerdefinierte Mapper für spezielle Anforderungen wie Cloud-Speicher oder dynamische Generierung:

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' nicht gefunden");
		}

		$url = $this->client->getPublicUrl($this->bucket, $reference);
		return Helpers::createAssetFromUrl($url);
	}
}

Registrieren Sie in der Konfiguration:

assets:
	mapping:
		cloud: CloudStorageMapper(@cloudClient, 'my-bucket')

Verwenden Sie wie jeden anderen Mapper:

{asset 'cloud:user-uploads/photo.jpg'}

Die Methode Helpers::createAssetFromUrl() erstellt automatisch den korrekten Asset-Typ basierend auf der Dateierweiterung.

Weitere Lektüre

Version: 1.0