nette/assets
Nette Assets is a lightweight asset pipeline for Nette apps. It helps you manage and reference CSS/JS, handle versioning/cache busting, and organize assets for development and production builds with a simple API and configuration.
Installation:
composer require nette/assets
Add to composer.json under require or require-dev based on your needs.
Basic Configuration:
Register the AssetManager in AppServiceProvider's boot() method:
use Nette\AssetManager;
public function boot()
{
$this->app->singleton(AssetManager::class, function ($app) {
$assetManager = new AssetManager();
$assetManager->setBasePath(public_path());
return $assetManager;
});
}
First Use Case: Create a Blade directive for easy asset references:
// In AppServiceProvider
Blade::directive('asset', function ($expression) {
return "<?php echo app('Nette\\AssetManager')->link(" . $expression . "); ?>";
});
Now use @asset('css/main.css') in Blade templates.
Verify Versioning:
Access an asset in production to confirm automatic versioning (e.g., /css/main.css?v=12345).
@asset('path/to/file.ext') in Blade.AssetManager:
$assetManager->setAutoVersioning(true); // Default: true in production
FontAsset for font files:
$font = $assetManager->createFontAsset('fonts/Inter.woff2');
$font->setCrossOrigin('anonymous'); // For CDN-hosted fonts
echo $font->getTag();
<link rel="preload"> for critical fonts in Blade:
@asset('fonts/Inter.woff2')->withAttributes(['as' => 'font', 'crossorigin'])
$assetManager->addMapper(new \Nette\AssetMapper\ViteMapper('http://localhost:5173'));
$assetManager->addDirectory(public_path('build'));
AssetManager into controllers/services:
public function __construct(private AssetManager $assetManager) {}
public function getDynamicAsset()
{
return $this->assetManager->link("dynamic-assets/{$this->userId}.js");
}
@asset('script.js')->withNonce(csp_nonce())
csp_nonce() is defined in your CSP middleware.Blade Directives: Extend the basic directive for attributes:
Blade::directive('asset', function ($expression) {
return "<?php echo app('Nette\\AssetManager')->link(" . $expression . ")->withAttributes(" . $expression . "Attributes); ?>";
});
Usage:
@asset('script.js', ['defer' => true])
Environment Awareness: Disable versioning in development:
if (app()->environment('local')) {
$assetManager->setAutoVersioning(false);
}
Custom Storage:
Implement Nette\AssetManager\IStorage for S3/Azure:
$assetManager->setStorage(new S3Storage($s3Client, 'my-bucket'));
Asset Groups: Organize assets by context (e.g., admin vs. frontend):
$adminAssets = new \Nette\AssetManager();
$adminAssets->addDirectory(public_path('admin-assets'));
AssetManager::createInlineAsset() for above-the-fold styles.Response middleware to add Cache-Control headers:
$assetManager->getAsset('main.css')->setCacheControl('public, max-age=31536000');
Path Resolution:
basePath isn’t set correctly.public_path('css/main.css')) or configure basePath:
$assetManager->setBasePath(public_path());
Versioning Conflicts:
$assetManager->setVersioningStrategy(new \Nette\AssetManager\FileVersioningStrategy());
Vite/Mix Sync:
nette/assets versioning.$assetManager->addMapper(new ViteMapper('http://localhost:5173'))
->setVersioning(false);
Font Loading:
crossorigin on self-hosted fonts may block rendering.$fontAsset = $assetManager->createFontAsset('fonts/Inter.woff2');
$fontAsset->setCrossOrigin('use-credentials'); // Or 'anonymous'
Blade Caching:
php artisan view:clear
Asset Existence: Check if an asset exists before linking:
if ($assetManager->hasAsset('missing.css')) {
echo $assetManager->link('missing.css');
}
Versioning Debug: Inspect the generated URL to verify versioning:
dd($assetManager->link('main.css')); // Should show ?v=12345
Storage Backend: Verify custom storage works:
$assetManager->setStorage(new CustomStorage());
dd($assetManager->getAsset('test.txt')->getUrl());
Vite Dev Server: Ensure the Vite dev server is running and the mapper URL is correct:
$mapper = new ViteMapper('http://localhost:5173');
dd($mapper->getUrl('app.js')); // Should proxy to Vite
Custom Asset Types:
Extend Nette\AssetManager\Asset for specialized assets (e.g., SVG sprites):
class SpriteAsset extends \Nette\AssetManager\Asset {
public function getTag(): string {
return sprintf('<img src="%s" class="sprite">', $this->getUrl());
}
}
Storage Adapters:
Implement Nette\AssetManager\IStorage for custom backends:
class S3Storage implements IStorage {
public function url(string $path): string {
return "https://my-bucket.s3.amazonaws.com/{$path}";
}
// Implement other methods...
}
Blade Extensions: Add more directives for common use cases:
Blade::directive('preload', function ($expression) {
return "<?php echo app('Nette\\AssetManager')->createAsset(" . $expression . ")->getPreloadTag(); ?>";
});
Middleware Integration: Add asset-specific headers via middleware:
public function handle($request, Closure $next) {
if ($request->isAssetRequest()) {
$response = $next($request);
$response->header('Cache-Control', 'public, max-age=31536000');
return $response;
}
return $next($request);
}
Testing:
Mock AssetManager in tests:
$assetManager = Mockery::mock(AssetManager::class);
$assetManager->shouldReceive('link')->with('test.css')->andReturn('<link href="/test.css?v=123">');
$this->app->instance(AssetManager::class, $assetManager);
How can I help you explore Laravel packages today?