Nette Assets
Cansado de gerenciar manualmente arquivos estáticos em suas aplicações web? Esqueça a codificação de caminhos, a invalidação de cache ou a preocupação com o versionamento de arquivos. Nette Assets transforma a maneira como você trabalha com imagens, folhas de estilo, scripts e outros recursos estáticos.
- Versionamento inteligente garante que os navegadores sempre carreguem os arquivos mais recentes
- Detecção automática de tipos e dimensões de arquivos
- Integração perfeita com Latte com tags intuitivas
- Arquitetura flexível suportando sistemas de arquivos, CDNs e Vite
- Carregamento preguiçoso para desempenho ideal
Por que Nette Assets?
Trabalhar com arquivos estáticos geralmente significa código repetitivo e propenso a erros. Você constrói URLs manualmente, adiciona parâmetros de versão para cache busting e lida com diferentes tipos de arquivos de forma diferente. Isso leva a um 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">
Com Nette Assets, toda essa complexidade desaparece:
{* Tudo automatizado - URL, versionamento, dimensões *}
<img n:asset="images/logo.png">
<link n:asset="css/style.css">
{* Ou simplesmente *}
{asset 'css/style.css'}
É isso! A biblioteca automaticamente:
- Adiciona parâmetros de versão com base na hora de modificação do arquivo
- Detecta dimensões da imagem e as inclui no HTML
- Gera o elemento HTML correto para cada tipo de arquivo
- Lida com ambientes de desenvolvimento e produção
Instalação
Instale Nette Assets usando Composer:
composer require nette/assets
Requer PHP 8.1 ou superior e funciona perfeitamente com Nette Framework, mas também pode ser usado de forma autônoma.
Primeiros Passos
Nette Assets funciona de imediato com configuração zero. Coloque seus arquivos estáticos no diretório
www/assets/
e comece a usá-los:
{* Exibe uma imagem com dimensões automáticas *}
{asset 'logo.png'}
{* Inclui uma folha de estilo com versionamento *}
{asset 'style.css'}
{* Carrega um módulo JavaScript *}
{asset 'app.js'}
Para mais controle sobre o HTML gerado, use o atributo n:asset
ou a função asset()
.
Como Funciona
Nette Assets é construído em torno de três conceitos centrais que o tornam poderoso e simples de usar:
Assets – Seus Arquivos Inteligentes
Um asset representa qualquer arquivo estático em sua aplicação. Cada arquivo se torna um objeto com propriedades somente leitura úteis:
$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 arquivo fornecem diferentes propriedades:
- Imagens: largura, altura, texto alternativo, carregamento preguiçoso
- Scripts: tipo de módulo, hashes de integridade, crossorigin
- Folhas de estilo: media queries, integridade
- Áudio/Vídeo: duração, dimensões
- Fontes: pré-carregamento adequado com CORS
A biblioteca detecta automaticamente os tipos de arquivo e cria a classe de asset apropriada.
Mappers – De Onde Vêm os Arquivos
Um mapper sabe como encontrar arquivos e criar URLs para eles. Você pode ter vários mappers para diferentes
propósitos – arquivos locais, CDN, armazenamento em nuvem ou ferramentas de construção (cada um deles tem um nome). O
FilesystemMapper
integrado lida com arquivos locais, enquanto o ViteMapper
se integra com ferramentas de
construção modernas.
Mappers são definidos na configuração.
Registry – Sua Interface Principal
O registry gerencia todos os mappers e fornece a API principal:
// Injeta o registry em seu serviço
public function __construct(
private Nette\Assets\Registry $assets
) {}
// Obtém 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 o mapper padrão
O registry seleciona automaticamente o mapper correto e armazena os resultados em cache para desempenho.
Trabalhando com Assets em PHP
O Registry fornece dois métodos para recuperar assets:
// Lança Nette\Assets\AssetNotFoundException se o arquivo não existir
$logo = $assets->getAsset('logo.png');
// Retorna null se o arquivo não existir
$banner = $assets->tryGetAsset('banner.jpg');
if ($banner) {
echo $banner->url;
}
Especificando Mappers
Você pode escolher explicitamente qual mapper usar:
// Usa o mapper padrão
$file = $assets->getAsset('document.pdf');
// Usa um mapper específico com prefixo
$image = $assets->getAsset('images:photo.jpg');
// Usa um mapper específico com sintaxe de array
$script = $assets->getAsset(['scripts', 'app.js']);
Propriedades e Tipos de Asset
Cada tipo de asset fornece propriedades somente leitura relevantes:
// Propriedades da imagem
$image = $assets->getAsset('photo.jpg');
echo $image->width; // 1920
echo $image->height; // 1080
echo $image->mimeType; // 'image/jpeg'
// Propriedades do script
$script = $assets->getAsset('app.js');
echo $script->type; // 'module' ou null
// Propriedades de áudio
$audio = $assets->getAsset('song.mp3');
echo $audio->duration; // duração em segundos
// Todos os assets podem ser convertidos para string (retorna URL)
$url = (string) $assets->getAsset('document.pdf');
Propriedades como dimensões ou duração são carregadas preguiçosamente apenas quando acessadas, mantendo a biblioteca rápida.
Usando Assets em Templates Latte
Nette Assets fornece integração intuitiva com Latte com tags e funções.
{asset}
A tag {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'}
A tag automaticamente:
- Detecta o tipo de asset e gera o HTML apropriado
- Inclui versionamento para cache busting
- Adiciona dimensões para imagens
- Define atributos corretos (tipo, mídia, etc.)
Quando usado dentro de atributos HTML, ele gera apenas a URL:
<div style="background-image: url({asset 'bg.jpg'})">
<img srcset="{asset 'logo@2x.png'} 2x">
n:asset
Para controle total sobre os atributos HTML:
{* O atributo n:asset preenche src, dimensões, etc. *}
<img n:asset="product.jpg" alt="Product" class="rounded">
{* Funciona com qualquer elemento relevante *}
<script n:asset="analytics.js" defer></script>
<link n:asset="print.css" media="print">
<audio n:asset="podcast.mp3" controls></audio>
Use variáveis e mappers:
{* Variáveis funcionam naturalmente *}
<img n:asset="$product->image">
{* Especifique o mapper com chaves *}
<img n:asset="images:{$product->image}">
{* Especifique o mapper com notação de array *}
<img n:asset="[images, $product->image]">
asset()
Para máxima flexibilidade, use a função asset()
:
{var $logo = asset('logo.png')}
<img src={$logo} width={$logo->width} height={$logo->height}>
{* Ou diretamente *}
<img src={asset('logo.png')} alt="Logo">
Assets Opcionais
Lide com assets ausentes graciosamente com {asset?}
, n:asset?
e tryAsset()
:
{* Tag opcional - não renderiza nada se o asset estiver ausente *}
{asset? 'optional-banner.jpg'}
{* Atributo opcional - ignora se o asset estiver ausente *}
<img n:asset?="user-avatar.jpg" alt="Avatar" class="avatar">
{* Com fallback *}
{var $avatar = tryAsset('user-avatar.jpg') ?? asset('default-avatar.jpg')}
<img n:asset=$avatar alt="Avatar">
{preload}
Melhore o desempenho de carregamento da página:
{* Na sua seção <head> *}
{preload 'critical.css'}
{preload 'important-font.woff2'}
{preload 'hero-image.jpg'}
Gera links de pré-carregamento apropriados:
<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">
Recursos Avançados
Detecção Automática de Extensão
Lida com múltiplos formatos automaticamente:
assets:
mapping:
images:
path: img
extension: [webp, jpg, png] # Tenta nesta ordem
Agora você pode requisitar sem extensão:
{* Encontra logo.webp, logo.jpg ou logo.png automaticamente *}
{asset 'images:logo'}
Perfeito para aprimoramento progressivo com formatos modernos.
Versionamento Inteligente
Os arquivos são automaticamente versionados com base na hora de modificação:
{asset 'style.css'}
{* Saída: <link rel="stylesheet" href="/assets/style.css?v=1699123456"> *}
Quando você atualiza o arquivo, o timestamp muda, forçando a atualização do cache do navegador.
Controle o versionamento por asset:
// Desativa o versionamento para um asset específico
$asset = $assets->getAsset('style.css', ['version' => false]);
// No Latte
{asset 'style.css', version: false}
Assets de Fonte
As fontes recebem tratamento especial com CORS adequado:
{* Pré-carregamento adequado com crossorigin *}
{preload 'fonts:OpenSans-Regular.woff2'}
{* Uso em CSS *}
<style>
@font-face {
font-family: 'Open Sans';
src: url('{asset 'fonts:OpenSans-Regular.woff2'}') format('woff2');
font-display: swap;
}
</style>
Mappers Personalizados
Crie mappers personalizados para necessidades especiais como armazenamento em nuvem ou geração 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' not found");
}
$url = $this->client->getPublicUrl($this->bucket, $reference);
return Helpers::createAssetFromUrl($url);
}
}
Registre na configuração:
assets:
mapping:
cloud: CloudStorageMapper(@cloudClient, 'my-bucket')
Use como qualquer outro mapper:
{asset 'cloud:user-uploads/photo.jpg'}
O método Helpers::createAssetFromUrl()
cria automaticamente o tipo de asset correto com base na extensão do
arquivo.