-
-
Notifications
You must be signed in to change notification settings - Fork 277
Expand file tree
/
Copy path@home.texy
More file actions
432 lines (295 loc) · 10.3 KB
/
Copy path@home.texy
File metadata and controls
432 lines (295 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
Nette Assets
************
<div class=perex>
Tired of manually managing static files in your web applications? Forget about hardcoding paths, dealing with cache invalidation, or worrying about file versioning. Nette Assets transforms how you work with images, stylesheets, scripts, and other static resources.
- **Smart versioning** ensures browsers always load the latest files
- **Automatic detection** of file types and dimensions
- **Seamless Latte integration** with intuitive tags
- **Flexible architecture** supporting filesystems, CDNs, and Vite
- **Lazy loading** for optimal performance
</div>
Why Nette Assets?
=================
Working with static files often means repetitive, error-prone code. You manually construct URLs, add version parameters for cache busting, and handle different file types differently. This leads to code like:
```latte
<img src="/images/logo.png?v=1699123456" width="200" height="100" alt="Logo">
<link rel="stylesheet" href="/css/style.css?v=2">
```
With Nette Assets, all this complexity disappears:
```latte
{* Everything automated - URL, versioning, dimensions *}
<img n:asset="images/logo.png">
<link n:asset="css/style.css">
{* Or just *}
{asset 'css/style.css'}
```
That's it! The library automatically:
- Adds version parameters based on file modification time
- Detects image dimensions and includes them in the HTML
- Generates the correct HTML element for each file type
- Handles both development and production environments
Installation
============
Install Nette Assets using [Composer|best-practices:composer]:
```shell
composer require nette/assets
```
It requires PHP 8.1 or higher and works perfectly with Nette Framework, but can also be used standalone.
First Steps
===========
Nette Assets works out of the box with zero configuration. Place your static files in the `www/assets/` directory and start using them:
```latte
{* Display an image with automatic dimensions *}
{asset 'logo.png'}
{* Include a stylesheet with versioning *}
{asset 'style.css'}
{* Load a JavaScript module *}
{asset 'app.js'}
```
For more control over the generated HTML, use the `n:asset` attribute or the `asset()` function.
How It Works
============
Nette Assets is built around three core concepts that make it powerful yet simple to use:
Assets - Your Files Made Smart
------------------------------
An **asset** represents any static file in your application. Each file becomes an object with useful readonly properties:
```php
$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'
```
Different file types provide different properties:
- **Images**: width, height, alternative text, lazy loading
- **Scripts**: module type, integrity hashes, crossorigin
- **Stylesheets**: media queries, integrity
- **Audio/Video**: duration, dimensions
- **Fonts**: proper preloading with CORS
The library automatically detects file types and creates the appropriate asset class.
Mappers - Where Files Come From
-------------------------------
A **mapper** knows how to find files and create URLs for them. You can have multiple mappers for different purposes - local files, CDN, cloud storage, or build tools (each of them has a name). The built-in `FilesystemMapper` handles local files, while `ViteMapper` integrates with modern build tools.
Mappers are defined in the [configuration].
Registry - Your Main Interface
------------------------------
The **registry** manages all mappers and provides the main API:
```php
// 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
```
The registry automatically selects the right mapper and caches results for performance.
Working with Assets in PHP
==========================
The Registry provides two methods for retrieving assets:
```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;
}
```
Specifying Mappers
------------------
You can explicitly choose which mapper to use:
```php
// 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']);
```
Asset Properties and Types
--------------------------
Each asset type provides relevant readonly properties:
```php
// 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');
```
.[note]
Properties like dimensions or duration are loaded lazily only when accessed, keeping the library fast.
Using Assets in Latte Templates
===============================
Nette Assets provides intuitive [Latte|latte:] integration with tags and functions.
`{asset}`
---------
The `{asset}` tag renders complete HTML elements:
```latte
{* 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'}
```
The tag automatically:
- Detects asset type and generates appropriate HTML
- Includes versioning for cache busting
- Adds dimensions for images
- Sets correct attributes (type, media, etc.)
When used inside HTML attributes, it outputs just the URL:
```latte
<div style="background-image: url({asset 'bg.jpg'})">
<img srcset="{asset 'logo@2x.png'} 2x">
```
`n:asset`
---------
For full control over HTML attributes:
```latte
{* 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>
```
Use variables and mappers:
```latte
{* 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()`
---------
For maximum flexibility, use the `asset()` function:
```latte
{var $logo = asset('logo.png')}
<img src={$logo} width={$logo->width} height={$logo->height}>
{* Or directly *}
<img src={asset('logo.png')} alt="Logo">
```
Optional Assets
---------------
Handle missing assets gracefully with `{asset?}`, `n:asset?` and `tryAsset()`:
```latte
{* 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}`
-----------
Improve page load performance:
```latte
{* In your <head> section *}
{preload 'critical.css'}
{preload 'important-font.woff2'}
{preload 'hero-image.jpg'}
```
Generates appropriate preload links:
```latte
<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">
```
Advanced Features
=================
Extension Auto-Detection
------------------------
Handle multiple formats automatically:
```neon
assets:
mapping:
images:
path: img
extension: [webp, jpg, png] # Try in order
```
Now you can request without extension:
```latte
{* Finds logo.webp, logo.jpg, or logo.png automatically *}
{asset 'images:logo'}
```
Perfect for progressive enhancement with modern formats.
Smart Versioning
----------------
Files are automatically versioned based on modification time:
```latte
{asset 'style.css'}
{* Output: <link rel="stylesheet" href="/assets/style.css?v=1699123456"> *}
```
When you update the file, the timestamp changes, forcing browser cache refresh.
Control versioning per asset:
```php
// Disable versioning for specific asset
$asset = $assets->getAsset('style.css', ['version' => false]);
// In Latte
{asset 'style.css', version: false}
```
Font Assets
-----------
Fonts get special treatment with proper CORS:
```latte
{* 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>
```
Custom Mappers
==============
Create custom mappers for special needs like cloud storage or dynamic generation:
```php
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);
}
}
```
Register in configuration:
```neon
assets:
mapping:
cloud: CloudStorageMapper(@cloudClient, 'my-bucket')
```
Use like any other mapper:
```latte
{asset 'cloud:user-uploads/photo.jpg'}
```
The `Helpers::createAssetFromUrl()` method automatically creates the correct asset type based on file extension.
Further Reading
===============
- [Nette Assets: Finally unified API for everything from images to Vite |https://blog.nette.org/en/introducing-nette-assets]