Assets
Asset management is crucial for modern web applications. Assets include CSS stylesheets, JavaScript files, images, fonts, and other static resources. Yii3 provides a comprehensive asset management system through the yiisoft/assets package that handles dependencies, optimization, and deployment of these resources.
Installation
The asset management functionality is provided by the yiisoft/assets package:
composer require yiisoft/assetsThis package is included by default in the yiisoft/app application template.
Basic Concepts
Asset Bundles
An asset bundle is a collection of related asset files (CSS, JavaScript, images) that are logically grouped together. Asset bundles can depend on other bundles, allowing for proper dependency management.
Asset Manager
The Asset Manager is responsible for: - Resolving asset bundle dependencies
- Publishing assets from protected directories to web-accessible locations - Combining and minifying assets (when configured) - Generating proper URLs for assets
Creating Asset Bundles
Basic Asset Bundle
Here's a simple asset bundle definition:
<?php
declare(strict_types=1);
namespace App\Asset;
use Yiisoft\Assets\AssetBundle;
final class MainAsset extends AssetBundle
{
public string $basePath = '@assets';
public string $baseUrl = '@assetsUrl';
public array $css = [
'css/main.css',
'css/responsive.css',
];
public array $js = [
'js/main.js',
'js/utils.js',
];
public array $depends = [
BootstrapAsset::class,
JqueryAsset::class,
];
}Asset Bundle Properties
Path Configuration:
$basePath- Physical path where asset files are located$baseUrl- Web-accessible URL path for assets$sourcePath- Source directory for assets that need to be published
Asset Files:
$css- Array of CSS files$js- Array of JavaScript files
Dependencies:
$depends- Array of other asset bundles this bundle depends on
Options:
$jsOptions- HTML attributes for JavaScript tags$cssOptions- HTML attributes for CSS link tags
Advanced Asset Bundle
<?php
declare(strict_types=1);
namespace App\Asset;
use Yiisoft\Assets\AssetBundle;
final class AdminAsset extends AssetBundle
{
public string $basePath = '@assets';
public string $baseUrl = '@assetsUrl';
// CSS files with media queries
public array $css = [
'css/admin/main.css',
['css/admin/print.css', 'media' => 'print'],
['css/admin/mobile.css', 'media' => 'screen and (max-width: 768px)'],
];
// JavaScript files with attributes
public array $js = [
'js/admin/core.js',
['js/admin/charts.js', 'defer' => true],
['js/admin/analytics.js', 'async' => true],
];
// Global options for all JS files in this bundle
public array $jsOptions = [
'data-admin' => 'true',
];
// Global options for all CSS files in this bundle
public array $cssOptions = [
'data-bundle' => 'admin',
];
public array $depends = [
MainAsset::class,
ChartJsAsset::class,
];
}Using Asset Bundles
In Controllers
Register asset bundles in your controllers or views:
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Asset\MainAsset;
use Psr\Http\Message\ResponseInterface;
use Yiisoft\Assets\AssetManager;
use Yiisoft\Yii\View\Renderer\ViewRenderer;
final class SiteController
{
public function __construct(
private ViewRenderer $viewRenderer,
private AssetManager $assetManager,
) {}
public function index(): ResponseInterface
{
// Register the asset bundle
$this->assetManager->register(MainAsset::class);
return $this->viewRenderer->render('index', [
'title' => 'Home Page',
]);
}
public function admin(): ResponseInterface
{
// Register multiple asset bundles
$this->assetManager->register([
MainAsset::class,
AdminAsset::class,
]);
return $this->viewRenderer->render('admin/dashboard');
}
}In Views
You can also register assets directly in views:
<?php
declare(strict_types=1);
use App\Asset\ProductAsset;
use Yiisoft\Assets\AssetManager;
/**
* @var \Yiisoft\View\WebView $this
* @var AssetManager $assetManager
* @var array $product
*/
// Register product-specific assets
$assetManager->register(ProductAsset::class);
?>
<div class="product-page">
<h1><?= Html::encode($product['name']) ?></h1>
<!-- Product content -->
</div>With WebView Integration
The recommended approach is to integrate with WebView for automatic asset rendering:
<?php
declare(strict_types=1);
use App\Asset\MainAsset;
/**
* @var \Yiisoft\View\WebView $this
* @var \Yiisoft\Assets\AssetManager $assetManager
*/
// Register assets
$assetManager->register(MainAsset::class);
// Add all registered assets to the view
$this->addCssFiles($assetManager->getCssFiles());
$this->addCssStrings($assetManager->getCssStrings());
$this->addJsFiles($assetManager->getJsFiles());
$this->addJsStrings($assetManager->getJsStrings());
$this->addJsVars($assetManager->getJsVars());
?>
<div class="page-content">
<!-- Your page content -->
</div>Asset Publishing
Source Path Publishing
When assets are located in non-web-accessible directories (like vendor packages), they need to be published:
<?php
declare(strict_types=1);
namespace App\Asset;
use Yiisoft\Assets\AssetBundle;
final class VendorAsset extends AssetBundle
{
// Source directory (not web accessible)
public string $sourcePath = '@vendor/company/package/assets';
// Will be published to web-accessible directory
public string $basePath = '@assets';
public string $baseUrl = '@assetsUrl';
public array $css = [
'styles.css',
];
public array $js = [
'script.js',
];
}Custom Publishing
You can also manually publish directories:
/**
* @var \Yiisoft\Assets\AssetManager $assetManager
*/
// Publish a directory
$publishedPath = $assetManager->publish('@vendor/company/package/assets');
// Get the published URL
$publishedUrl = $assetManager->getPublishedUrl('@vendor/company/package/assets');Third-party Library Assets
jQuery Asset Bundle
<?php
declare(strict_types=1);
namespace App\Asset;
use Yiisoft\Assets\AssetBundle;
final class JqueryAsset extends AssetBundle
{
public string $basePath = '@assets';
public string $baseUrl = '@assetsUrl';
public array $js = [
'js/jquery-3.6.0.min.js',
];
// Or use CDN
public array $jsOptions = [
'integrity' => 'sha256-...',
'crossorigin' => 'anonymous',
];
}Bootstrap Asset Bundle
<?php
declare(strict_types=1);
namespace App\Asset;
use Yiisoft\Assets\AssetBundle;
final class BootstrapAsset extends AssetBundle
{
public string $basePath = '@assets';
public string $baseUrl = '@assetsUrl';
public array $css = [
'css/bootstrap.min.css',
];
public array $js = [
'js/bootstrap.bundle.min.js',
];
public array $depends = [
JqueryAsset::class, // Bootstrap requires jQuery
];
}CDN Assets
For CDN-hosted assets, you can specify full URLs:
<?php
declare(strict_types=1);
namespace App\Asset;
use Yiisoft\Assets\AssetBundle;
final class CdnAsset extends AssetBundle
{
public array $css = [
'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css',
];
public array $js = [
'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js',
];
public array $jsOptions = [
'integrity' => 'sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p',
'crossorigin' => 'anonymous',
];
}Asset Configuration
Application Configuration
Configure asset management in your application configuration:
config/web/params.php
return [
'yiisoft/assets' => [
// Base path for published assets
'basePath' => '@webroot/assets',
// Base URL for assets
'baseUrl' => '@web/assets',
// Asset converter configuration
'converter' => [
'commands' => [
'scss' => ['sass', '{from}', '{to}', '--style=compressed'],
'ts' => ['tsc', '{from}', '--outFile', '{to}'],
],
],
],
];Environment-specific Assets
Configure different assets for different environments:
<?php
declare(strict_types=1);
namespace App\Asset;
use Yiisoft\Assets\AssetBundle;
final class MainAsset extends AssetBundle
{
public string $basePath = '@assets';
public string $baseUrl = '@assetsUrl';
public array $css = [];
public array $js = [];
public function __construct()
{
if (YII_ENV_DEV) {
// Development assets (unminified)
$this->css = ['css/main.css', 'css/debug.css'];
$this->js = ['js/main.js', 'js/debug.js'];
} else {
// Production assets (minified)
$this->css = ['css/main.min.css'];
$this->js = ['js/main.min.js'];
}
}
}Asset Optimization
Asset Combination
Combine multiple CSS or JavaScript files into single files:
/**
* @var \Yiisoft\Assets\AssetManager $assetManager
*/
// Enable asset combination
$assetManager->setCombine(true);
// Set combination options
$assetManager->setCombineOptions([
'css' => true, // Combine CSS files
'js' => true, // Combine JavaScript files
]);Asset Compression
Configure asset compression for production:
// In your asset manager configuration
'converter' => [
'commands' => [
'css' => ['cleancss', '{from}', '-o', '{to}'],
'js' => ['uglifyjs', '{from}', '-o', '{to}', '--compress', '--mangle'],
],
],Working with Asset Converter
SCSS/SASS Compilation
<?php
declare(strict_types=1);
namespace App\Asset;
use Yiisoft\Assets\AssetBundle;
final class ScssAsset extends AssetBundle
{
public string $sourcePath = '@app/assets/scss';
public string $basePath = '@assets';
public string $baseUrl = '@assetsUrl';
public array $css = [
'main.scss', // Will be converted to main.css
'components.scss',
];
}TypeScript Compilation
<?php
declare(strict_types=1);
namespace App\Asset;
use Yiisoft\Assets\AssetBundle;
final class TypeScriptAsset extends AssetBundle
{
public string $sourcePath = '@app/assets/ts';
public string $basePath = '@assets';
public string $baseUrl = '@assetsUrl';
public array $js = [
'main.ts', // Will be converted to main.js
'utils.ts',
];
}Practical Examples
Complete Application Asset Structure
assets/
├── css/
│ ├── main.css # Main application styles
│ ├── admin.css # Admin-specific styles
│ └── mobile.css # Mobile-specific styles
├── js/
│ ├── main.js # Main application JavaScript
│ ├── admin.js # Admin functionality
│ └── vendor/ # Third-party libraries
│ ├── jquery.min.js
│ └── bootstrap.min.js
├── images/
│ ├── logo.png
│ └── icons/
└── fonts/
├── main.woff2
└── main.woffComplete Asset Bundle Setup
<?php
declare(strict_types=1);
namespace App\Asset;
use Yiisoft\Assets\AssetBundle;
// Base asset bundle
final class AppAsset extends AssetBundle
{
public string $basePath = '@assets';
public string $baseUrl = '@assetsUrl';
public array $css = [
'css/main.css',
];
public array $js = [
'js/main.js',
];
public array $depends = [
JqueryAsset::class,
];
}
// Admin-specific bundle
final class AdminAsset extends AssetBundle
{
public string $basePath = '@assets';
public string $baseUrl = '@assetsUrl';
public array $css = [
'css/admin.css',
];
public array $js = [
'js/admin.js',
];
public array $depends = [
AppAsset::class,
BootstrapAsset::class,
];
}
// Mobile-specific bundle
final class MobileAsset extends AssetBundle
{
public string $basePath = '@assets';
public string $baseUrl = '@assetsUrl';
public array $css = [
['css/mobile.css', 'media' => 'screen and (max-width: 768px)'],
];
public array $depends = [
AppAsset::class,
];
}Best Practices
- Organize by functionality: Group related assets into logical bundles
- Manage dependencies: Properly declare dependencies between bundles
- Use meaningful names: Name your asset bundles clearly
- Environment optimization: Use minified assets in production
- CDN consideration: Use CDN for popular libraries when appropriate
- Version your assets: Include version numbers in filenames for cache busting
- Minimize HTTP requests: Combine related assets when possible
- Optimize file sizes: Compress and minify assets for production
Troubleshooting
Common Issues
Asset not found:
- Check that the asset file exists in the specified path
- Verify
$basePathand$baseUrlare configured correctly - Ensure assets are published if using
$sourcePath
Dependencies not loading:
- Verify the dependency bundles are properly registered
- Check for circular dependencies
- Ensure dependency bundles are correctly configured
Assets not appearing in HTML:
- Make sure you're calling
$this->addCssFiles()and$this->addJsFiles()in your layout - Verify that
$this->head(),$this->beginBody(), and$this->endBody()are called in the layout
Permission issues:
- Check that the web server has write permissions to the assets directory
- Verify the published assets directory is web-accessible