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.
Install the Package
composer require nette/assets
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;
});
}
Create a Blade Directive
Add this to AppServiceProvider's boot():
Blade::directive('asset', function ($expression) {
return "<?php echo app('Nette\\AssetManager')->link((string) {$expression}; ?>";
});
First Usage Replace hardcoded paths in Blade:
<link rel="stylesheet" href="{{ asset('css/main.css') }}">
<script src="{{ asset('js/app.js') }}"></script>
// In a controller or service
$fontAsset = $this->app->make(AssetManager::class)
->createFontAsset('fonts/Inter.woff2')
->setCrossOrigin('anonymous');
echo $fontAsset->getTag(); // <link rel="preload" href="/fonts/Inter.woff2?v=1.23" as="font" type="font/woff2" crossorigin="anonymous">
// Register a directory (e.g., public/css)
$assetManager->addProvider(new \Nette\AssetManager\Providers\DirectoryProvider(
public_path('css'),
'css'
));
// Blade usage:
<link rel="stylesheet" href="{{ asset('css/main.css') }}">
// Custom storage adapter (e.g., S3)
$assetManager->setStorage(new \Nette\AssetManager\Storage\S3Storage(
$s3Client,
'my-bucket',
'https://cdn.example.com'
));
// Generate a signed URL for a user-uploaded file
$userAsset = $assetManager->createAsset('/uploads/avatar.jpg');
$userAsset->setExpires('+1 hour');
echo $userAsset->getUrl();
// In AppServiceProvider
$assetManager = new AssetManager();
$assetManager->setBasePath(public_path());
// Disable versioning in development
if (app()->environment('development')) {
$assetManager->setVersioning(false);
}
// Enable preloading for production
if (app()->environment('production')) {
$assetManager->setPreload(['fonts/Inter.woff2']);
}
// Register Vite dev server mapper
$assetManager->addMapper(new \Nette\AssetManager\Mappers\ViteMapper(
'http://localhost:5173',
['css', 'js'] // Only proxy these extensions
));
// Blade usage (points to Vite dev server)
<link rel="stylesheet" href="{{ asset('resources/css/app.css') }}">
// Register built assets (after running `npm run build`)
$assetManager->addProvider(new \Nette\AssetManager\Providers\DirectoryProvider(
public_path('build'),
'build'
));
// Blade usage (points to compiled files)
<script src="{{ asset('build/app.js') }}"></script>
// Add a directive for font assets
Blade::directive('font', function ($expression) {
return "<?php echo app('Nette\\AssetManager')->createFontAsset((string) {$expression})->getTag(); ?>";
});
// Usage in Blade:
@font('fonts/Inter.woff2', ['crossorigin' => 'anonymous'])
// In a middleware or service
$assetManager = app(AssetManager::class);
$nonce = $assetManager->generateNonce();
// Store nonce in session/Blade
session(['asset_nonce' => $nonce]);
// Blade usage:
<script src="{{ asset('js/app.js')->withNonce(session('asset_nonce')) }}"></script>
Path Resolution Failures
public_path('css')) and validate directories during boot.AssetManager::setDebugMode(true) to log missing assets.Versioning Conflicts
?v=1.0) may break Vite/Mix hashed filenames.$assetManager->setVersioning(function ($asset) {
return md5($asset->getUrl());
});
Font Loading Blockers
crossorigin.crossorigin for external fonts:
$fontAsset->setCrossOrigin('anonymous');
Caching Headaches
$assetManager->setCacheControl('public, max-age=31536000, immutable');
Vite/Mix Mismatches
@vite() directives won’t work with nette/assets.@vite() with @asset() and manually handle Vite’s manifest:
// Parse Vite's manifest.json and register assets
$manifest = json_decode(file_get_contents(public_path('build/manifest.json')), true);
foreach ($manifest as $entry => $hash) {
$assetManager->addProvider(new \Nette\AssetManager\Providers\StaticProvider(
"build/{$hash}",
$entry
));
}
$assetManager->setDebugMode(true); // Logs missing assets to storage/logs/nette-assets.log
$asset = $assetManager->createAsset('css/main.css');
dump($asset->getTag()); // Inspect generated HTML
dump($assetManager->getStorage()->getAsset('css/main.css')); // Verify file exists
Custom Storage Adapters
Implement \Nette\AssetManager\IStorage for S3, Azure, etc.:
class CustomStorage implements IStorage {
public function getAsset(string $path): ?string {
// Fetch from custom backend
}
public function getUrl(string $path): string {
// Generate signed URL
}
}
Asset Mappers
Extend \Nette\AssetManager\IMapper for custom URL transformations:
class CustomMapper implements IMapper {
public function map(string $asset): ?string {
return str_replace('old-', 'new-', $asset);
}
}
Blade Directives Create reusable directives for common assets:
Blade::directive('icon', function ($expression) {
return "<?php echo app('Nette\\AssetManager')->createAsset('icons/{$expression}')->getTag(); ?>";
});
$assetManager->setPreload([
'fonts/Inter.woff2',
'css/main.css'
]);
$asset = $assetManager->createAsset('js/lazy.js');
$asset->setAttribute('loading', 'lazy');
echo $asset->getTag();
$assetManager->setCacheControl('public, max-age=31536000, immutable');
Service Container Integration
Bind the AssetManager to Laravel’s container for dependency injection:
$this->app->bind(\Nette\AssetManager::class, function ($app) {
$assetManager = new \Nette\AssetManager();
$assetManager->setBasePath($app->basePath('public'));
return $assetManager;
});
View Composers Inject assets into views via composers:
View::composer('*', function ($view) {
$view->with('cssAssets', [
$
How can I help you explore Laravel packages today?