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

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.

Leitura adicional

versão: 1.0