Nette Assets
Stanchi di gestire a mano i file statici nelle vostre applicazioni web? Dimenticate i percorsi scritti a mano, l'invalidazione della cache e le preoccupazioni sul versionamento dei file. Nette Assets trasforma il modo in cui lavorate con immagini, fogli di stile, script e altre risorse statiche.
- Il versionamento intelligente garantisce che i browser carichino sempre i file più recenti
- Rilevamento automatico dei tipi di file e delle dimensioni
- Integrazione fluida con Latte grazie a tag intuitivi
- Architettura flessibile che supporta filesystem, CDN e Vite
- Caricamento pigro per prestazioni ottimali
Perché Nette Assets?
Lavorare con i file statici significa spesso codice ripetitivo e soggetto a errori. Costruite gli URL a mano, aggiungete i parametri di versione per invalidare la cache e trattate in modo diverso i vari tipi di file. Il che porta a codice come questo:
<img src="/images/logo.png?v=1699123456" width="200" height="100" alt="Logo">
<link rel="stylesheet" href="/css/style.css?v=2">
Con Nette Assets tutta questa complessità sparisce:
{* tutto automatizzato: URL, versionamento, dimensioni *}
<img n:asset="images/logo.png">
<link n:asset="css/style.css">
{* oppure solo *}
{asset 'css/style.css'}
Ecco fatto! La libreria automaticamente:
- aggiunge i parametri di versione in base all'ora di modifica del file
- rileva le dimensioni delle immagini e le inserisce nell'HTML
- genera l'elemento HTML corretto per ogni tipo di file
- gestisce sia l'ambiente di sviluppo sia quello di produzione
Installazione
Installate Nette Assets con Composer:
composer require nette/assets
Richiede PHP 8.1 o superiore e funziona perfettamente con il Nette Framework, ma si può usare anche da solo.
Primi passi
Nette Assets funziona subito senza alcuna configurazione. Mettete i vostri file statici nella directory
www/assets/ e cominciate a usarli:
{* mostra un'immagine con le dimensioni automatiche *}
{asset 'logo.png'}
{* include un foglio di stile con il versionamento *}
{asset 'style.css'}
{* carica uno script *}
{asset 'app.js'}
Per un maggiore controllo sull'HTML generato usate l'attributo n:asset oppure la funzione
asset().
Come funziona
Nette Assets è costruito attorno a tre concetti fondamentali che lo rendono potente e allo stesso tempo semplice da usare:
Asset: i vostri file resi intelligenti
Un asset rappresenta qualsiasi file statico della vostra applicazione. Ogni file diventa un oggetto con utili proprietà readonly:
$image = $assets->getAsset('photo.jpg');
echo $image->url; // '/assets/photo.jpg?v=1699123456'
echo $image->file; // '/var/www/assets/photo.jpg' (percorso locale, oppure null)
echo $image->width; // 1920
echo $image->height; // 1080
echo $image->mimeType; // 'image/jpeg'
Tipi di file diversi offrono proprietà diverse:
- Immagini: larghezza, altezza, testo alternativo, caricamento pigro
- Script: tipo di modulo, hash di integrità, crossorigin
- Fogli di stile: media query, integrità
- Audio/video: durata, dimensioni (solo video)
- Font: preloading corretto con CORS
La libreria rileva automaticamente i tipi di file e crea la classe di asset appropriata.
Mapper: da dove vengono i file
Un mapper sa come trovare i file e creare gli URL per essi. Potete avere più mapper per scopi diversi: file locali,
CDN, storage cloud o strumenti di build (ognuno ha un nome). Il FilesystemMapper integrato si occupa dei file
locali, mentre ViteMapper si integra con i moderni strumenti di build.
I mapper si definiscono nella configurazione.
Registry: la vostra interfaccia principale
Il registry gestisce tutti i mapper e offre l'API principale:
// fatevi iniettare il registry nel vostro servizio
public function __construct(
private Nette\Assets\Registry $assets
) {}
// ottenete gli asset dai vari mapper
$logo = $this->assets->getAsset('images:logo.png'); // mapper 'images'
$app = $this->assets->getAsset('app:main.js'); // mapper 'app'
$style = $this->assets->getAsset('style.css'); // usa il mapper predefinito
Il registry sceglie automaticamente il mapper giusto e mette in cache i risultati per le prestazioni.
Lavorare con gli asset in PHP
Il Registry offre due metodi per ottenere gli asset:
// lancia Nette\Assets\AssetNotFoundException se il file non esiste
$logo = $assets->getAsset('logo.png');
// restituisce null se il file non esiste
$banner = $assets->tryGetAsset('banner.jpg');
if ($banner) {
echo $banner->url;
}
Indicare i mapper
Potete scegliere esplicitamente quale mapper usare:
// usa il mapper predefinito
$file = $assets->getAsset('document.pdf');
// usa un mapper specifico con il prefisso
$image = $assets->getAsset('images:photo.jpg');
// usa un mapper specifico con la sintassi ad array
$script = $assets->getAsset(['scripts', 'app.js']);
Proprietà e tipi degli asset
Ogni tipo di asset offre le proprietà readonly pertinenti:
// proprietà di un'immagine
$image = $assets->getAsset('photo.jpg');
echo $image->width; // 1920
echo $image->height; // 1080
echo $image->mimeType; // 'image/jpeg'
// proprietà di uno script
$script = $assets->getAsset('app.js');
echo $script->type; // null ('module' per i punti di ingresso di Vite)
// proprietà di un audio
$audio = $assets->getAsset('song.mp3');
echo $audio->duration; // durata in secondi
// tutti gli asset si possono convertire in stringa (restituisce l'URL)
$url = (string) $assets->getAsset('document.pdf');
Proprietà come le dimensioni o la durata vengono caricate pigramente solo quando vi si accede, il che mantiene la libreria veloce.
Per un'analisi statica precisa installate l'estensione nette/phpstan-rules. PHPStan conosce allora il tipo concreto di
ogni asset, quindi getAsset('photo.jpg') viene inteso come ImageAsset e l'accesso a
->width non provoca alcun errore.
Usare gli asset nei template Latte
Nette Assets offre un'integrazione intuitiva con Latte tramite tag e funzioni.
{asset}
Il tag {asset} renderizza elementi HTML completi:
{* renderizza: <img src="/assets/hero.jpg?v=123" width="1920" height="1080"> *}
{asset 'hero.jpg'}
{* renderizza: <script src="/assets/app.js?v=456"></script> *}
{asset 'app.js'}
{* renderizza: <link rel="stylesheet" href="/assets/style.css?v=789"> *}
{asset 'style.css'}
Il tag automaticamente:
- rileva il tipo di asset e genera l'HTML appropriato
- include il versionamento per invalidare la cache
- aggiunge le dimensioni per le immagini
- imposta gli attributi corretti (type, media ecc.)
Quando si usa dentro un attributo HTML oppure dentro gli elementi <style> e <script>,
stampa solo l'URL:
<div style="background-image: url({asset 'bg.jpg'})">
<img srcset="{asset 'logo@2x.png'} 2x">
n:asset
Per il pieno controllo sugli attributi HTML:
{* l'attributo n:asset riempie src, dimensioni ecc. *}
<img n:asset="product.jpg" alt="Product" class="rounded">
{* funziona con qualsiasi elemento pertinente *}
<script n:asset="analytics.js" defer></script>
<link n:asset="print.css" media="print">
<audio n:asset="podcast.mp3" controls></audio>
Usate variabili e mapper:
{* le variabili funzionano naturalmente *}
<img n:asset="$product->image">
{* indicate il mapper con le parentesi graffe *}
<img n:asset="images:{$product->image}">
{* indicate il mapper con la notazione ad array *}
<img n:asset="[images, $product->image]">
n:asset funziona anche su <a>, dove riempie href, e su <link>,
dove crea un hint di preload:
<a n:asset="hero.jpg">Scarica l'immagine</a>
Notate che le varianti <a> e <link> funzionano solo per gli asset renderizzabili
(un'immagine, uno script e così via), mai per un GenericAsset come un PDF.
Per le immagini basta impostare solo width (oppure solo height) e l'altra dimensione viene calcolata
automaticamente per mantenere le proporzioni:
{* height viene completato dalle proporzioni *}
<img n:asset="product.jpg" width="200">
asset()
Per la massima flessibilità usate la funzione asset():
{var $logo = asset('logo.png')}
<img src={$logo} width={$logo->width} height={$logo->height}>
{* oppure direttamente *}
<img src={asset('logo.png')} alt="Logo">
Asset facoltativi
Gestite con eleganza gli asset mancanti con {asset?}, n:asset? e tryAsset():
{* tag facoltativo: non renderizza nulla se l'asset manca *}
{asset? 'optional-banner.jpg'}
{* attributo facoltativo: viene saltato se l'asset manca *}
<img n:asset?="user-avatar.jpg" alt="Avatar" class="avatar">
{* con ripiego *}
{var $avatar = tryAsset('user-avatar.jpg') ?? asset('default-avatar.jpg')}
<img n:asset=$avatar alt="Avatar">
{preload}
Migliorate le prestazioni di caricamento della pagina:
{* nella vostra sezione <head> *}
{preload 'critical.css'}
{preload 'important-font.woff2'}
{preload 'hero-image.jpg'}
Genera i link di preload appropriati:
<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">
Quando la vostra risposta imposta un header Content-Security-Policy con un nonce, Nette
aggiunge automaticamente l'attributo nonce corrispondente a ogni elemento <script>,
<link> e <style> generato, così non vengono bloccati dalla policy di sicurezza del
browser.
Funzionalità avanzate
Rilevamento automatico dell'estensione
Gestite automaticamente più formati:
assets:
mapping:
images:
path: img
extension: [webp, jpg, png] # prova nell'ordine
Ora potete richiederli senza estensione:
{* trova automaticamente logo.webp, logo.jpg oppure logo.png *}
{asset 'images:logo'}
Perfetto per il miglioramento progressivo con i formati moderni.
Versionamento intelligente
I file vengono versionati automaticamente in base all'ora di modifica:
{asset 'style.css'}
{* output: <link rel="stylesheet" href="/assets/style.css?v=1699123456"> *}
Quando aggiornate il file, il timestamp cambia e costringe il browser ad aggiornare la cache.
Governate il versionamento per singolo asset:
// disattiva il versionamento per un asset specifico
$asset = $assets->getAsset('style.css', ['version' => false]);
{* in Latte *}
{asset 'style.css', version: false}
La stessa sintassi riferimento, chiave: valore passa le opzioni anche a n:asset e a
{preload}:
<img n:asset="photo.jpg, version: false">
{preload 'style.css', version: false}
Asset di tipo font
I font ricevono un trattamento particolare con il CORS corretto:
{* preload corretto con crossorigin *}
{preload 'fonts:OpenSans-Regular.woff2'}
{* uso nel CSS *}
<style>
@font-face {
font-family: 'Open Sans';
src: url('{asset 'fonts:OpenSans-Regular.woff2'}') format('woff2');
font-display: swap;
}
</style>
Mapper personalizzati
Create mapper personalizzati per esigenze particolari, come lo storage cloud o la generazione dinamica:
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);
}
}
Registratelo nella configurazione:
assets:
mapping:
cloud: CloudStorageMapper(@cloudClient, 'my-bucket')
Usatelo come qualsiasi altro mapper:
{asset 'cloud:user-uploads/photo.jpg'}
Il metodo Helpers::createAssetFromUrl() crea automaticamente il tipo di asset corretto in base all'estensione
del file.
I tipi di asset che implementano l'interfaccia Nette\Assets\HtmlRenderable (immagini, script, stili e così via)
possono essere renderizzati da {asset} come elemento HTML completo. Gli altri tipi di file diventano un
GenericAsset (per esempio un PDF), che non si può renderizzare come elemento HTML ma offre comunque un URL (e altri
metadati). Provare a renderizzare un asset del genere come elemento HTML lancia Nette\InvalidArgumentException;
potete comunque usarne l'URL dentro un attributo.