Nette Assets
¿Cansado de gestionar manualmente archivos estáticos en sus aplicaciones web? Olvídese de codificar rutas, lidiar con la invalidación de la caché o preocuparse por el versionado de archivos. Nette Assets transforma la forma en que trabaja con imágenes, hojas de estilo, scripts y otros recursos estáticos.
- El versionado inteligente garantiza que los navegadores siempre carguen los archivos más recientes
- Detección automática de tipos de archivo y dimensiones
- Integración perfecta con Latte con etiquetas intuitivas
- Arquitectura flexible que soporta sistemas de archivos, CDNs y Vite
- Carga diferida para un rendimiento óptimo
¿Por qué Nette Assets?
Trabajar con archivos estáticos a menudo significa código repetitivo y propenso a errores. Usted construye URLs manualmente, añade parámetros de versión para la eliminación de caché y maneja diferentes tipos de archivos de manera distinta. Esto lleva a un código como:
<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, toda esta complejidad desaparece:
{* Todo automatizado - URL, versionado, dimensiones *}
<img n:asset="images/logo.png">
<link n:asset="css/style.css">
{* O simplemente *}
{asset 'css/style.css'}
¡Eso es todo! La librería automáticamente:
- Añade parámetros de versión basados en la hora de modificación del archivo
- Detecta las dimensiones de la imagen y las incluye en el HTML
- Genera el elemento HTML correcto para cada tipo de archivo
- Maneja tanto entornos de desarrollo como de producción
Instalación
Instale Nette Assets usando Composer:
composer require nette/assets
Requiere PHP 8.1 o superior y funciona perfectamente con Nette Framework, pero también puede usarse de forma independiente.
Primeros Pasos
Nette Assets funciona de forma inmediata sin configuración. Coloque sus archivos estáticos en el directorio
www/assets/
y empiece a usarlos:
{* Muestra una imagen con dimensiones automáticas *}
{asset 'logo.png'}
{* Incluye una hoja de estilo con versionado *}
{asset 'style.css'}
{* Carga un módulo JavaScript *}
{asset 'app.js'}
Para un mayor control sobre el HTML generado, use el atributo n:asset
o la función asset()
.
Cómo Funciona
Nette Assets se construye alrededor de tres conceptos fundamentales que lo hacen potente y, al mismo tiempo, sencillo de usar:
Assets – Sus Archivos Hechos Inteligentes
Un asset representa cualquier archivo estático en su aplicación. Cada archivo se convierte en un objeto con propiedades de solo lectura útiles:
$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'
Diferentes tipos de archivo proporcionan diferentes propiedades:
- Imágenes: ancho, alto, texto alternativo, carga diferida
- Scripts: tipo de módulo, hashes de integridad, crossorigin
- Hojas de estilo: media queries, integridad
- Audio/Video: duración, dimensiones
- Fuentes: precarga adecuada con CORS
La librería detecta automáticamente los tipos de archivo y crea la clase de asset apropiada.
Mappers – De Dónde Vienen los Archivos
Un mapper sabe cómo encontrar archivos y crear URLs para ellos. Puede tener varios mappers para diferentes propósitos:
archivos locales, CDN, almacenamiento en la nube o herramientas de construcción (cada uno de ellos tiene un nombre). El
FilesystemMapper
incorporado maneja los archivos locales, mientras que ViteMapper
se integra con las
herramientas de construcción modernas.
Los mappers se definen en la configuración.
Registry – Su Interfaz Principal
El registry gestiona todos los mappers y proporciona la API principal:
// Inyecta el registro en su servicio
public function __construct(
private Nette\Assets\Registry $assets
) {}
// Obtiene assets de diferentes mappers
$logo = $this->assets->getAsset('images:logo.png'); // mapper 'image'
$app = $this->assets->getAsset('app:main.js'); // mapper 'app'
$style = $this->assets->getAsset('style.css'); // usa el mapper predeterminado
El registro selecciona automáticamente el mapper correcto y almacena en caché los resultados para mejorar el rendimiento.
Trabajando con Assets en PHP
El Registry proporciona dos métodos para recuperar assets:
// Lanza Nette\Assets\AssetNotFoundException si el archivo no existe
$logo = $assets->getAsset('logo.png');
// Devuelve null si el archivo no existe
$banner = $assets->tryGetAsset('banner.jpg');
if ($banner) {
echo $banner->url;
}
Especificando Mappers
Puede elegir explícitamente qué mapper usar:
// Usar el mapper predeterminado
$file = $assets->getAsset('document.pdf');
// Usar un mapper específico con prefijo
$image = $assets->getAsset('images:photo.jpg');
// Usar un mapper específico con sintaxis de array
$script = $assets->getAsset(['scripts', 'app.js']);
Propiedades y Tipos de Assets
Cada tipo de asset proporciona propiedades de solo lectura relevantes:
// Propiedades de la imagen
$image = $assets->getAsset('photo.jpg');
echo $image->width; // 1920
echo $image->height; // 1080
echo $image->mimeType; // 'image/jpeg'
// Propiedades del script
$script = $assets->getAsset('app.js');
echo $script->type; // 'module' o null
// Propiedades del audio
$audio = $assets->getAsset('song.mp3');
echo $audio->duration; // duración en segundos
// Todos los assets pueden convertirse a string (devuelve la URL)
$url = (string) $assets->getAsset('document.pdf');
Las propiedades como las dimensiones o la duración se cargan de forma diferida solo cuando se acceden, manteniendo la librería rápida.
Usando Assets en Plantillas Latte
Nette Assets proporciona una integración intuitiva con Latte mediante etiquetas y funciones.
{asset}
La etiqueta {asset}
renderiza elementos HTML completos:
{* Renderiza: <img src="/assets/hero.jpg?v=123" width="1920" height="1080"> *}
{asset 'hero.jpg'}
{* Renderiza: <script src="/assets/app.js?v=456" type="module"></script> *}
{asset 'app.js'}
{* Renderiza: <link rel="stylesheet" href="/assets/style.css?v=789"> *}
{asset 'style.css'}
La etiqueta automáticamente:
- Detecta el tipo de asset y genera el HTML apropiado
- Incluye versionado para la eliminación de caché
- Añade dimensiones para las imágenes
- Establece los atributos correctos (type, media, etc.)
Cuando se usa dentro de atributos HTML, solo genera la URL:
<div style="background-image: url({asset 'bg.jpg'})">
<img srcset="{asset 'logo@2x.png'} 2x">
n:asset
Para un control total sobre los atributos HTML:
{* El atributo n:asset rellena src, dimensiones, etc. *}
<img n:asset="product.jpg" alt="Producto" class="rounded">
{* Funciona con cualquier elemento relevante *}
<script n:asset="analytics.js" defer></script>
<link n:asset="print.css" media="print">
<audio n:asset="podcast.mp3" controls></audio>
Use variables y mappers:
{* Las variables funcionan de forma natural *}
<img n:asset="$product->image">
{* Especificar mapper con llaves *}
<img n:asset="images:{$product->image}">
{* Especificar mapper con notación de array *}
<img n:asset="[images, $product->image]">
asset()
Para una máxima flexibilidad, use la función asset()
:
{var $logo = asset('logo.png')}
<img src={$logo} width={$logo->width} height={$logo->height}>
{* O directamente *}
<img src={asset('logo.png')} alt="Logo">
Assets Opcionales
Maneje los assets que faltan con elegancia usando {asset?}
, n:asset?
y tryAsset()
:
{* Etiqueta opcional - no renderiza nada si falta el asset *}
{asset? 'optional-banner.jpg'}
{* Atributo opcional - se omite si falta el asset *}
<img n:asset?="user-avatar.jpg" alt="Avatar" class="avatar">
{* Con fallback *}
{var $avatar = tryAsset('user-avatar.jpg') ?? asset('default-avatar.jpg')}
<img n:asset=$avatar alt="Avatar">
{preload}
Mejore el rendimiento de carga de la página:
{* En su sección <head> *}
{preload 'critical.css'}
{preload 'important-font.woff2'}
{preload 'hero-image.jpg'}
Genera enlaces de precarga apropiados:
<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">
Características Avanzadas
Detección Automática de Extensión
Maneje múltiples formatos automáticamente:
assets:
mapping:
images:
path: img
extension: [webp, jpg, png] # Intentar en orden
Ahora puede solicitar sin extensión:
{* Encuentra logo.webp, logo.jpg o logo.png automáticamente *}
{asset 'images:logo'}
Perfecto para la mejora progresiva con formatos modernos.
Versionado Inteligente
Los archivos se versionan automáticamente según la hora de modificación:
{asset 'style.css'}
{* Salida: <link rel="stylesheet" href="/assets/style.css?v=1699123456"> *}
Cuando actualiza el archivo, la marca de tiempo cambia, forzando la actualización de la caché del navegador.
Controle el versionado por asset:
// Deshabilitar el versionado para un asset específico
$asset = $assets->getAsset('style.css', ['version' => false]);
// En Latte
{asset 'style.css', version: false}
Assets de Fuentes
Las fuentes reciben un tratamiento especial con CORS adecuado:
{* Precarga adecuada con crossorigin *}
{preload 'fonts:OpenSans-Regular.woff2'}
{* Usar en CSS *}
<style>
@font-face {
font-family: 'Open Sans';
src: url('{asset 'fonts:OpenSans-Regular.woff2'}') format('woff2');
font-display: swap;
}
</style>
Mappers Personalizados
Cree mappers personalizados para necesidades especiales como almacenamiento en la nube o generación dinámica:
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' no encontrado");
}
$url = $this->client->getPublicUrl($this->bucket, $reference);
return Helpers::createAssetFromUrl($url);
}
}
Registre en la configuración:
assets:
mapping:
cloud: CloudStorageMapper(@cloudClient, 'my-bucket')
Use como cualquier otro mapper:
{asset 'cloud:user-uploads/photo.jpg'}
El método Helpers::createAssetFromUrl()
crea automáticamente el tipo de asset correcto basándose en la
extensión del archivo.