Nette Assets
Устали вручную управлять статическими файлами в ваших веб-приложениях? Забудьте о жестком кодировании путей, проблемах с инвалидацией кэша или беспокойстве о версионировании файлов. Nette Assets преобразует ваш способ работы с изображениями, таблицами стилей, скриптами и другими статическими ресурсами.
- Умное версионирование гарантирует, что браузеры всегда загружают последние версии файлов
- Автоматическое определение типов и размеров файлов
- Бесшовная интеграция с Latte с интуитивно понятными тегами
- Гибкая архитектура, поддерживающая файловые системы, CDN и Vite
- Ленивая загрузка для оптимальной производительности
Зачем Nette Assets?
Работа со статическими файлами часто означает повторяющийся, подверженный ошибкам код. Вы вручную конструируете URL, добавляете параметры версии для обхода кэша и по-разному обрабатываете различные типы файлов. Это приводит к такому коду:
<img src="/images/logo.png?v=1699123456" width="200" height="100" alt="Logo">
<link rel="stylesheet" href="/css/style.css?v=2">
С Nette Assets вся эта сложность исчезает:
{* Everything automated - URL, versioning, dimensions *}
<img n:asset="images/logo.png">
<link n:asset="css/style.css">
{* Or just *}
{asset 'css/style.css'}
Вот и все! Библиотека автоматически:
- Добавляет параметры версии на основе времени модификации файла
- Определяет размеры изображения и включает их в HTML
- Генерирует правильный HTML-элемент для каждого типа файла
- Обрабатывает как среды разработки, так и производственные среды
Установка
Установите Nette Assets с помощью Composer:
composer require nette/assets
Требуется PHP 8.1 или выше, и он отлично работает с Nette Framework, но также может использоваться автономно.
Первые шаги
Nette Assets работает из коробки без какой-либо конфигурации. Разместите
свои статические файлы в каталоге www/assets/
и начните их
использовать:
{* Display an image with automatic dimensions *}
{asset 'logo.png'}
{* Include a stylesheet with versioning *}
{asset 'style.css'}
{* Load a JavaScript module *}
{asset 'app.js'}
Для большего контроля над генерируемым HTML используйте атрибут
n:asset
или функцию asset()
.
Как это работает
Nette Assets построен на трех основных концепциях, которые делают его мощным, но простым в использовании:
Активы – Ваши файлы стали умнее
Актив представляет собой любой статический файл в вашем приложении. Каждый файл становится объектом с полезными свойствами только для чтения:
$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'
Различные типы файлов предоставляют различные свойства:
- Изображения: ширина, высота, альтернативный текст, ленивая загрузка
- Скрипты: тип модуля, хеши целостности, crossorigin
- Таблицы стилей: медиа-запросы, целостность
- Аудио/Видео: продолжительность, размеры
- Шрифты: правильная предварительная загрузка с CORS
Библиотека автоматически определяет типы файлов и создает соответствующий класс актива.
Сопоставители – Откуда берутся файлы
Сопоставитель знает, как находить файлы и создавать для них URL. У
вас может быть несколько сопоставителей для разных целей – локальные
файлы, CDN, облачное хранилище или инструменты сборки (каждый из них
имеет имя). Встроенный FilesystemMapper
обрабатывает локальные файлы, а
ViteMapper
интегрируется с современными инструментами сборки.
Сопоставители определяются в конфигурации.
Реестр – Ваш основной интерфейс
Реестр управляет всеми сопоставителями и предоставляет основной API:
// Inject the registry in your service
public function __construct(
private Nette\Assets\Registry $assets
) {}
// Get assets from different mappers
$logo = $this->assets->getAsset('images:logo.png'); // 'image' mapper
$app = $this->assets->getAsset('app:main.js'); // 'app' mapper
$style = $this->assets->getAsset('style.css'); // uses default mapper
Реестр автоматически выбирает правильный сопоставитель и кэширует результаты для повышения производительности.
Работа с активами в PHP
Реестр предоставляет два метода для получения активов:
// Throws Nette\Assets\AssetNotFoundException if file doesn't exist
$logo = $assets->getAsset('logo.png');
// Returns null if file doesn't exist
$banner = $assets->tryGetAsset('banner.jpg');
if ($banner) {
echo $banner->url;
}
Указание сопоставителей
Вы можете явно выбрать, какой сопоставитель использовать:
// Use default mapper
$file = $assets->getAsset('document.pdf');
// Use specific mapper with prefix
$image = $assets->getAsset('images:photo.jpg');
// Use specific mapper with array syntax
$script = $assets->getAsset(['scripts', 'app.js']);
Свойства и типы активов
Каждый тип актива предоставляет соответствующие свойства только для чтения:
// Image properties
$image = $assets->getAsset('photo.jpg');
echo $image->width; // 1920
echo $image->height; // 1080
echo $image->mimeType; // 'image/jpeg'
// Script properties
$script = $assets->getAsset('app.js');
echo $script->type; // 'module' or null
// Audio properties
$audio = $assets->getAsset('song.mp3');
echo $audio->duration; // duration in seconds
// All assets can be cast to string (returns URL)
$url = (string) $assets->getAsset('document.pdf');
Свойства, такие как размеры или продолжительность, загружаются лениво только при обращении к ним, что обеспечивает быструю работу библиотеки.
Использование активов в Latte-шаблонах
Nette Assets обеспечивает интуитивно понятную интеграцию с Latte с помощью тегов и функций.
{asset}
Тег {asset}
отображает полные HTML-элементы:
{* Renders: <img src="/assets/hero.jpg?v=123" width="1920" height="1080"> *}
{asset 'hero.jpg'}
{* Renders: <script src="/assets/app.js?v=456" type="module"></script> *}
{asset 'app.js'}
{* Renders: <link rel="stylesheet" href="/assets/style.css?v=789"> *}
{asset 'style.css'}
Тег автоматически:
- Определяет тип актива и генерирует соответствующий HTML
- Включает версионирование для обхода кэша
- Добавляет размеры для изображений
- Устанавливает правильные атрибуты (type, media и т.д.)
При использовании внутри HTML-атрибутов он выводит только URL:
<div style="background-image: url({asset 'bg.jpg'})">
<img srcset="{asset 'logo@2x.png'} 2x">
n:asset
Для полного контроля над HTML-атрибутами:
{* The n:asset attribute fills in src, dimensions, etc. *}
<img n:asset="product.jpg" alt="Product" class="rounded">
{* Works with any relevant element *}
<script n:asset="analytics.js" defer></script>
<link n:asset="print.css" media="print">
<audio n:asset="podcast.mp3" controls></audio>
Используйте переменные и сопоставители:
{* Variables work naturally *}
<img n:asset="$product->image">
{* Specify mapper with curly brackets *}
<img n:asset="images:{$product->image}">
{* Specify mapper with array notation *}
<img n:asset="[images, $product->image]">
asset()
Для максимальной гибкости используйте функцию asset()
:
{var $logo = asset('logo.png')}
<img src={$logo} width={$logo->width} height={$logo->height}>
{* Or directly *}
<img src={asset('logo.png')} alt="Logo">
Опциональные активы
Избегайте ошибок при отсутствии активов с помощью {asset?}
,
n:asset?
и tryAsset()
:
{* Optional tag - renders nothing if asset missing *}
{asset? 'optional-banner.jpg'}
{* Optional attribute - skips if asset missing *}
<img n:asset?="user-avatar.jpg" alt="Avatar" class="avatar">
{* With fallback *}
{var $avatar = tryAsset('user-avatar.jpg') ?? asset('default-avatar.jpg')}
<img n:asset=$avatar alt="Avatar">
{preload}
Улучшите производительность загрузки страницы:
{* In your <head> section *}
{preload 'critical.css'}
{preload 'important-font.woff2'}
{preload 'hero-image.jpg'}
Генерирует соответствующие ссылки предварительной загрузки:
<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">
Расширенные возможности
Автоматическое определение расширения
Автоматическая обработка нескольких форматов:
assets:
mapping:
images:
path: img
extension: [webp, jpg, png] # Try in order
Теперь вы можете запрашивать без расширения:
{* Finds logo.webp, logo.jpg, or logo.png automatically *}
{asset 'images:logo'}
Идеально подходит для прогрессивного улучшения с помощью современных форматов.
Умное версионирование
Файлы автоматически версионируются на основе времени модификации:
{asset 'style.css'}
{* Output: <link rel="stylesheet" href="/assets/style.css?v=1699123456"> *}
При обновлении файла метка времени изменяется, что принудительно обновляет кэш браузера.
Управление версионированием для каждого актива:
// Disable versioning for specific asset
$asset = $assets->getAsset('style.css', ['version' => false]);
// In Latte
{asset 'style.css', version: false}
Активы шрифтов
Шрифты получают специальную обработку с правильным CORS:
{* Proper preload with crossorigin *}
{preload 'fonts:OpenSans-Regular.woff2'}
{* Use in CSS *}
<style>
@font-face {
font-family: 'Open Sans';
src: url('{asset 'fonts:OpenSans-Regular.woff2'}') format('woff2');
font-display: swap;
}
</style>
Пользовательские сопоставители
Создавайте пользовательские сопоставители для особых нужд, таких как облачное хранилище или динамическая генерация:
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);
}
}
Зарегистрируйте в конфигурации:
assets:
mapping:
cloud: CloudStorageMapper(@cloudClient, 'my-bucket')
Используйте как любой другой сопоставитель:
{asset 'cloud:user-uploads/photo.jpg'}
Метод Helpers::createAssetFromUrl()
автоматически создает правильный тип
актива на основе расширения файла.