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()
автоматично створює правильний тип
активу на основі розширення файлу.