|
|
|
Assets
|
|
|
|
======
|
|
|
|
|
|
|
|
An asset in Yii is a file that may be referenced in a Web page. It can be a CSS file, a JavaScript file, an image
|
|
|
|
or video file, etc. Assets are located in Web-accessible directories and are directly served by Web servers.
|
|
|
|
|
|
|
|
It is often preferable to manage assets programmatically. For example, when you use the [[yii\jui\DatePicker]] widget
|
|
|
|
in a page, it will automatically include the required CSS and JavaScript files, instead of asking you to manually
|
|
|
|
find these files and include them. And when you upgrade the widget to a new version, it will automatically use
|
|
|
|
the new version of the asset files. In this tutorial, we will describe the powerful asset management capability
|
|
|
|
provided in Yii.
|
|
|
|
|
|
|
|
|
|
|
|
## Asset Bundles <a name="asset-bundles"></a>
|
|
|
|
|
|
|
|
Yii manages assets in the unit of *asset bundle*. An asset bundle is simply a collection of assets located
|
|
|
|
in a directory. When you register an asset bundle in a [view](structure-views.md), it will include the CSS and
|
|
|
|
JavaScript files in the bundle in the rendered Web page.
|
|
|
|
|
|
|
|
|
|
|
|
## Defining Asset Bundles <a name="defining-asset-bundles"></a>
|
|
|
|
|
|
|
|
Asset bundles are specified as PHP classes extending from [[yii\web\AssetBundle]]. The name of a bundle is simply
|
|
|
|
its corresponding PHP class name which should be [autoloadable](concept-autoloading.md). In an asset bundle class,
|
|
|
|
you would typically specify where the assets are located, what CSS and JavaScript files the bundle contains, and
|
|
|
|
how the bundle depends on other bundles.
|
|
|
|
|
|
|
|
The following code defines the main asset bundle used by [the basic application template](start-installation.md):
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace app\assets;
|
|
|
|
|
|
|
|
use yii\web\AssetBundle;
|
|
|
|
|
|
|
|
class AppAsset extends AssetBundle
|
|
|
|
{
|
|
|
|
public $basePath = '@webroot';
|
|
|
|
public $baseUrl = '@web';
|
|
|
|
public $css = [
|
|
|
|
'css/site.css',
|
|
|
|
];
|
|
|
|
public $js = [
|
|
|
|
];
|
|
|
|
public $depends = [
|
|
|
|
'yii\web\YiiAsset',
|
|
|
|
'yii\bootstrap\BootstrapAsset',
|
|
|
|
];
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The above `AppAsset` class specifies that the asset files are located under the `@webroot` directory which
|
|
|
|
is corresponding to the URL `@web`; the bundle contains a single CSS file `css/site.css` and no JavaScript file;
|
|
|
|
the bundle depends on two other bundles: [[yii\web\YiiAsset]] and [[yii\bootstrap\BootstrapAsset]]. More detailed
|
|
|
|
explanation about the properties of [[yii\web\AssetBundle]] can be found in the following:
|
|
|
|
|
|
|
|
* [[yii\web\AssetBundle::sourcePath|sourcePath]]: specifies the root directory that contains the asset files in
|
|
|
|
this bundle. This property should be set if the root directory is not Web accessible. Otherwise, you should
|
|
|
|
set the [[yii\web\AssetBundle::basePath|basePath]] property and [[yii\web\AssetBundle::baseUrl|baseUrl]], instead.
|
|
|
|
[Path aliases](concept-aliases.md) can be used here.
|
|
|
|
* [[yii\web\AssetBundle::basePath|basePath]]: specifies a Web-accessible directory that contains the asset files in
|
|
|
|
this bundle. When you specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property,
|
|
|
|
the [asset manager](#asset-manager) will publish the assets in this bundle to a Web-accessible directory
|
|
|
|
and overwrite this property accordingly. You should set this property if your asset files are already in
|
|
|
|
a Web-accessible directory and do not need asset publishing. [Path aliases](concept-aliases.md) can be used here.
|
|
|
|
* [[yii\web\AssetBundle::baseUrl|baseUrl]]: specifies the URL corresponding to the directory
|
|
|
|
[[yii\web\AssetBundle::basePath|basePath]]. Like [[yii\web\AssetBundle::basePath|basePath]],
|
|
|
|
if you specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property, the [asset manager](#asset-manager)
|
|
|
|
will publish the assets and overwrite this property accordingly. [Path aliases](concept-aliases.md) can be used here.
|
|
|
|
* [[yii\web\AssetBundle::js|js]]: an array listing the JavaScript files contained in this bundle. Note that only
|
|
|
|
forward slash "/" should be used as directory separators. Each JavaScript file can be specified in one of the
|
|
|
|
following two formats:
|
|
|
|
- a relative path representing a local JavaScript file (e.g. `js/main.js`). The actual path of the file
|
|
|
|
can be determined by prepending [[yii\web\AssetManager::basePath]] to the relative path, and the actual URL
|
|
|
|
of the file can be determined by prepending [[yii\web\AssetManager::baseUrl]] to the relative path.
|
|
|
|
- an absolute URL representing an external JavaScript file. For example,
|
|
|
|
`http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js` or
|
|
|
|
`//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js`.
|
|
|
|
* [[yii\web\AssetBundle::css|css]]: an array listing the CSS files contained in this bundle. The format of this array
|
|
|
|
is the same as that of [[yii\web\AssetBundle::js|js]].
|
|
|
|
* [[yii\web\AssetBundle::depends|depends]]: an array listing the names of the asset bundles that this bundle depends on
|
|
|
|
(to be explained shortly).
|
|
|
|
* [[yii\web\AssetBundle::jsOptions|jsOptions]]: specifies the options that will be passed to the
|
|
|
|
[[yii\web\View::registerJsFile()]] method when it is called to register *every* JavaScript file in this bundle.
|
|
|
|
* [[yii\web\AssetBundle::cssOptions|cssOptions]]: specifies the options that will be passed to the
|
|
|
|
[[yii\web\View::registerCssFile()]] method when it is called to register *every* CSS file in this bundle.
|
|
|
|
* [[yii\web\AssetBundle::publishOptions|publishOptions]]: specifies the options that will be passed to the
|
|
|
|
[[yii\web\AssetManager::publish()]] method when it is called to publish source asset files to a Web directory.
|
|
|
|
This is only used if you specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property.
|
|
|
|
|
|
|
|
|
|
|
|
### Asset Locations <a name="asset-locations"></a>
|
|
|
|
|
|
|
|
Assets, based on their location, can be classified as:
|
|
|
|
|
|
|
|
* source assets: the asset files are located together with PHP source code which cannot be directly accessed via Web.
|
|
|
|
In order to use source assets in a page, they should be copied to a Web directory and turned into the so-called
|
|
|
|
published assets. This process is called *asset publishing* which will be described in detail shortly.
|
|
|
|
* published assets: the asset files are located in a Web directory and can thus be directly accessed via Web.
|
|
|
|
* external assets: the asset files are located on a Web server that is different from the one hosting your Web
|
|
|
|
application.
|
|
|
|
|
|
|
|
When defining an asset bundle class, if you specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property,
|
|
|
|
it means any assets listed using relative paths will be considered as source assets. If you do not specify this property,
|
|
|
|
it means those assets are published assets (you should therefore specify [[yii\web\AssetBundle::basePath|basePath]] and
|
|
|
|
[[yii\web\AssetBundle::baseUrl|baseUrl]] to let Yii know where they are located.)
|
|
|
|
|
|
|
|
It is recommended that you place assets belonging to an application in a Web directory to avoid the unnecessary asset
|
|
|
|
publishing process. This is why `AppAsset` in the prior example specifies [[yii\web\AssetBundle::basePath|basePath]]
|
|
|
|
instead of [[yii\web\AssetBundle::sourcePath|sourcePath]].
|
|
|
|
|
|
|
|
For [extensions](structure-extensions.md), because their assets are located together with their source code
|
|
|
|
in directories that are not Web accessible, you have to specify the [[yii\web\AssetBundle::sourcePath|sourcePath]]
|
|
|
|
property when defining asset bundle classes for them.
|
|
|
|
|
|
|
|
> Note: Do not use `@webroot/assets` as the [[yii\web\AssetBundle::sourcePath|source path]].
|
|
|
|
This directory is used by default by the [[yii\web\AssetManager|asset manager]] to save the asset files
|
|
|
|
published from their source location. Any content in this directory are considered temporarily and may be subject
|
|
|
|
to removal.
|
|
|
|
|
|
|
|
|
|
|
|
### Asset Dependencies <a name="asset-dependencies"></a>
|
|
|
|
|
|
|
|
When you include multiple CSS or JavaScript files in a Web page, they have to follow certain orders to avoid
|
|
|
|
overriding issues. For example, if you are using a jQuery UI widget in a Web page, you have to make sure
|
|
|
|
the jQuery JavaScript file is included before the jQuery UI JavaScript file. We call such ordering the dependencies
|
|
|
|
among assets.
|
|
|
|
|
|
|
|
Asset dependencies are mainly specified through the [[yii\web\AssetBundle::depends]] property.
|
|
|
|
In the `AppAsset` example, the asset bundle depends on two other asset bundles: [[yii\web\YiiAsset]] and
|
|
|
|
[[yii\bootstrap\BootstrapAsset]], which means the CSS and JavaScript files in `AppAsset` will be included *after*
|
|
|
|
those files in the two dependent bundles.
|
|
|
|
|
|
|
|
Asset dependencies are transitive. This means if bundle A depends on B which depends on C, A will depend on C, too.
|
|
|
|
|
|
|
|
|
|
|
|
### Asset Options <a name="asset-options"></a>
|
|
|
|
|
|
|
|
You can specify the [[yii\web\AssetBundle::cssOptions|cssOptions]] and [[yii\web\AssetBundle::jsOptions|jsOptions]]
|
|
|
|
properties to customize the way that CSS and JavaScript files are included in a page. The values of these properties
|
|
|
|
will be passed to the [[yii\web\View::registerCssFile()]] and [[yii\web\View::registerJsFile()]] methods, respectively, when
|
|
|
|
they are called by the [view](structure-views.md) to include CSS and JavaScript files.
|
|
|
|
|
|
|
|
> Note: The options you set in a bundle class apply to *every* CSS/JavaScript file in the bundle. If you want to
|
|
|
|
use different options for different files, you should create separate asset bundles, and use one set of options
|
|
|
|
in each bundle.
|
|
|
|
|
|
|
|
For example, to conditionally include a CSS file for browsers that are IE9 or above, you can use the following option:
|
|
|
|
|
|
|
|
```php
|
|
|
|
public $cssOptions = ['condition' => 'lte IE9'];
|
|
|
|
```
|
|
|
|
|
|
|
|
This will cause a CSS file in the bundle to be included using the following HTML tags:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<!--[if lte IE9]>
|
|
|
|
<link rel="stylesheet" href="path/to/foo.css">
|
|
|
|
<![endif]-->
|
|
|
|
```
|
|
|
|
|
|
|
|
To wrap link tag with `<noscript>` the following can be used:
|
|
|
|
|
|
|
|
```php
|
|
|
|
public $cssOptions = ['noscript' => true];
|
|
|
|
```
|
|
|
|
|
|
|
|
To include a JavaScript file in the head section of a page (by default, JavaScript files are included at the end
|
|
|
|
of the body section), use the following option:
|
|
|
|
|
|
|
|
```php
|
|
|
|
public $jsOptions = ['position' => \yii\web\View::POS_HEAD];
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Bower and NPM Assets <a name="bower-npm-assets"></a>
|
|
|
|
|
|
|
|
Most JavaScript/CSS package are managed by [Bower](http://bower.io/) and/or [NPM](https://www.npmjs.org/).
|
|
|
|
If your application or extension is using such a package, it is recommended that you follow these steps to manage
|
|
|
|
the assets in the library:
|
|
|
|
|
|
|
|
1. Modify the `composer.json` file of your application or extension and list the package in the `require` entry.
|
|
|
|
You should use `bower-asset/PackageName` (for Bower packages) or `npm-asset/PackageName` (for NPM packages)
|
|
|
|
to refer to the library.
|
|
|
|
2. Create an asset bundle class and list the JavaScript/CSS files that you plan to use in your application or extension.
|
|
|
|
You should specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property as `@bower/PackageName` or `@npm/PackageName`.
|
|
|
|
This is because Composer will install the Bower or NPM package in the directory corresponding to this alias.
|
|
|
|
|
|
|
|
> Note: Some packages may put all their distributed files in a subdirectory. If this is the case, you should specify
|
|
|
|
the subdirectory as the value of [[yii\web\AssetBundle::sourcePath|sourcePath]]. For example, [[yii\web\JqueryAsset]]
|
|
|
|
uses `@bower/jquery/dist` instead of `@bower/jquery`.
|
|
|
|
|
|
|
|
|
|
|
|
## Using Asset Bundles <a name="using-asset-bundles"></a>
|
|
|
|
|
|
|
|
To use an asset bundle, register it with a [view](structure-views.md) by calling the [[yii\web\AssetBundle::register()]]
|
|
|
|
method. For example, in a view template you can register an asset bundle like the following:
|
|
|
|
|
|
|
|
```php
|
|
|
|
use app\assets\AppAsset;
|
|
|
|
AppAsset::register($this); // $this represents the view object
|
|
|
|
```
|
|
|
|
|
|
|
|
If you are registering an asset bundle in other places, you should provide the needed view object. For example,
|
|
|
|
to register an asset bundle in a [widget](structure-widgets.md) class, you can get the view object by `$this->view`.
|
|
|
|
|
|
|
|
When an asset bundle is registered with a view, behind the scene Yii will register all its dependent asset bundles.
|
|
|
|
And if an asset bundle is located in a directory inaccessible through the Web, it will be published to a Web directory.
|
|
|
|
Later when the view renders a page, it will generate `<link>` and `<script>` tags for the CSS and JavaScript files
|
|
|
|
listed in the registered bundles. The order of these tags is determined by the dependencies among
|
|
|
|
the registered bundles and the order of the assets listed in the [[yii\web\AssetBundle::css]] and [[yii\web\AssetBundle::js]]
|
|
|
|
properties.
|
|
|
|
|
|
|
|
|
|
|
|
### Customizing Asset Bundles <a name="customizing-asset-bundles"></a>
|
|
|
|
|
|
|
|
Yii manages asset bundles through an application component named `assetManager` which is implemented by [[yii\web\AssetManager]].
|
|
|
|
By configuring the [[yii\web\AssetManager::bundles]] property, it is possible to customize the behavior of an asset bundle.
|
|
|
|
For example, the default [[yii\web\JqueryAsset]] asset bundle uses the `jquery.js` file from the installed
|
|
|
|
jquery Bower package. To improve the availability and performance, you may want to use a version hosted by Google.
|
|
|
|
This can be achieved by configuring `assetManager` in the application configuration like the following:
|
|
|
|
|
|
|
|
```php
|
|
|
|
return [
|
|
|
|
// ...
|
|
|
|
'components' => [
|
|
|
|
'assetManager' => [
|
|
|
|
'bundles' => [
|
|
|
|
'yii\web\JqueryAsset' => [
|
|
|
|
'sourcePath' => null, // do not publish the bundle
|
|
|
|
'js' => [
|
|
|
|
'//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
|
|
|
|
]
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
];
|
|
|
|
```
|
|
|
|
|
|
|
|
You can configure multiple asset bundles similarly through [[yii\web\AssetManager::bundles]]. The array keys
|
|
|
|
should be the class names (without the leading backslash) of the asset bundles, and the array values should
|
|
|
|
be the corresponding [configuration arrays](concept-configurations.md).
|
|
|
|
|
|
|
|
> Tip: You can conditionally choose which assets to use in an asset bundle. The following example shows how
|
|
|
|
> to use `jquery.js` in the development environment and `jquery.min.js` otherwise:
|
|
|
|
>
|
|
|
|
> ```php
|
|
|
|
> 'yii\web\JqueryAsset' => [
|
|
|
|
> 'js' => [
|
|
|
|
> YII_ENV_DEV ? 'jquery.js' : 'jquery.min.js'
|
|
|
|
> ]
|
|
|
|
> ],
|
|
|
|
> ```
|
|
|
|
|
|
|
|
You can disable one or multiple asset bundles by associating `false` with the names of the asset bundles
|
|
|
|
that you want to disable. When you register a disabled asset bundle with a view, none of its dependent bundles
|
|
|
|
will be registered, and the view will also not include any of the assets in the bundle in the page it renders.
|
|
|
|
For example, to disable [[yii\web\JqueryAsset]], you can use the following configuration:
|
|
|
|
|
|
|
|
```php
|
|
|
|
return [
|
|
|
|
// ...
|
|
|
|
'components' => [
|
|
|
|
'assetManager' => [
|
|
|
|
'bundles' => [
|
|
|
|
'yii\web\JqueryAsset' => false,
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
];
|
|
|
|
```
|
|
|
|
|
|
|
|
You can also disable *all* asset bundles by setting [[yii\web\AssetManager::bundles]] as `false`.
|
|
|
|
|
|
|
|
|
|
|
|
### Asset Mapping <a name="asset-mapping"></a>
|
|
|
|
|
|
|
|
Sometimes you want to "fix" incorrect/incompatible asset file paths used in multiple asset bundles. For example,
|
|
|
|
bundle A uses `jquery.min.js` of version 1.11.1, and bundle B uses `jquery.js` of version 2.1.1. While you can
|
|
|
|
fix the problem by customizing each bundle, an easier way is to use the *asset map* feature to map incorrect assets
|
|
|
|
to the desired ones. To do so, configure the [[yii\web\AssetManager::assetMap]] property like the following:
|
|
|
|
|
|
|
|
```php
|
|
|
|
return [
|
|
|
|
// ...
|
|
|
|
'components' => [
|
|
|
|
'assetManager' => [
|
|
|
|
'assetMap' => [
|
|
|
|
'jquery.js' => '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
];
|
|
|
|
```
|
|
|
|
|
|
|
|
The keys of [[yii\web\AssetManager::assetMap|assetMap]] are the asset names that you want to fix, and the values
|
|
|
|
are the desired asset paths. When you register an asset bundle with a view, each relative asset file in its
|
|
|
|
[[yii\web\AssetBundle::css|css]] and [[yii\web\AssetBundle::js|js]] arrays will be examined against this map.
|
|
|
|
If any of the keys is found to be the last part of an asset file (which is prefixed with [[yii\web\AssetBundle::sourcePath]]
|
|
|
|
if available), the corresponding value will replace the asset and be registered with the view.
|
|
|
|
For example, an asset file `my/path/to/jquery.js` matches a key `jquery.js`.
|
|
|
|
|
|
|
|
> Note: Only assets specified using relative paths are subject to asset mapping. And the target asset paths
|
|
|
|
should be either absolute URLs or paths relative to [[yii\web\AssetManager::basePath]].
|
|
|
|
|
|
|
|
|
|
|
|
### Asset Publishing <a name="asset-publishing"></a>
|
|
|
|
|
|
|
|
As aforementioned, if an asset bundle is located in a directory that is not Web accessible, its assets will be copied
|
|
|
|
to a Web directory when the bundle is being registered with a view. This process is called *asset publishing*, and is done
|
|
|
|
automatically by the [[yii\web\AssetManager|asset manager]].
|
|
|
|
|
|
|
|
By default, assets are published to the directory `@webroot/assets` which corresponds to the URL `@web/assets`.
|
|
|
|
You may customize this location by configuring the [[yii\web\AssetManager::basePath|basePath]] and
|
|
|
|
[[yii\web\AssetManager::baseUrl|baseUrl]] properties.
|
|
|
|
|
|
|
|
Instead of publishing assets by file copying, you may consider using symbolic links, if your OS and Web server allow.
|
|
|
|
This feature can be enabled by setting [[yii\web\AssetManager::linkAssets|linkAssets]] to be true.
|
|
|
|
|
|
|
|
```php
|
|
|
|
return [
|
|
|
|
// ...
|
|
|
|
'components' => [
|
|
|
|
'assetManager' => [
|
|
|
|
'linkAssets' => true,
|
|
|
|
],
|
|
|
|
],
|
|
|
|
];
|
|
|
|
```
|
|
|
|
|
|
|
|
With the above configuration, the asset manager will create a symbolic link to the source path of an asset bundle
|
|
|
|
when it is being published. This is faster than file copying and can also ensure that the published assets are
|
|
|
|
always up-to-date.
|
|
|
|
|
|
|
|
|
|
|
|
## Commonly Used Asset Bundles <a name="common-asset-bundles"></a>
|
|
|
|
|
|
|
|
The core Yii code has defined many asset bundles. Among them, the following bundles are commonly used and may
|
|
|
|
be referenced in your application or extension code.
|
|
|
|
|
|
|
|
- [[yii\web\YiiAsset]]: It mainly includes the `yii.js` file which implements a mechanism of organizing JavaScript code
|
|
|
|
in modules. It also provides special support for `data-method` and `data-confirm` attributes and other useful features.
|
|
|
|
- [[yii\web\JqueryAsset]]: It includes the `jquery.js` file from the jQuery bower package.
|
|
|
|
- [[yii\bootstrap\BootstrapAsset]]: It includes the CSS file from the Twitter Bootstrap framework.
|
|
|
|
- [[yii\bootstrap\BootstrapPluginAsset]]: It includes the JavaScript file from the Twitter Bootstrap framework for
|
|
|
|
supporting Bootstrap JavaScript plugins.
|
|
|
|
- [[yii\jui\JuiAsset]]: It includes the CSS and JavaScript files from the jQuery UI library.
|
|
|
|
|
|
|
|
If your code depends on jQuery, jQuery UI or Bootstrap, you should use these predefined asset bundles rather than
|
|
|
|
creating your own versions. If the default setting of these bundles do not satisfy your needs, you may customize them
|
|
|
|
as described in the [Customizing Asset Bundle](#customizing-asset-bundles) subsection.
|
|
|
|
|
|
|
|
|
|
|
|
## Asset Conversion <a name="asset-conversion"></a>
|
|
|
|
|
|
|
|
Instead of directly writing CSS and/or JavaScript code, developers often write them in some extended syntax and
|
|
|
|
use special tools to convert it into CSS/JavaScript. For example, for CSS code you may use [LESS](http://lesscss.org/)
|
|
|
|
or [SCSS](http://sass-lang.com/); and for JavaScript you may use [TypeScript](http://www.typescriptlang.org/).
|
|
|
|
|
|
|
|
You can list the asset files in extended syntax in [[yii\web\AssetBundle::css|css]] and [[yii\web\AssetBundle::js|js]]
|
|
|
|
in an asset bundle. For example,
|
|
|
|
|
|
|
|
```php
|
|
|
|
class AppAsset extends AssetBundle
|
|
|
|
{
|
|
|
|
public $basePath = '@webroot';
|
|
|
|
public $baseUrl = '@web';
|
|
|
|
public $css = [
|
|
|
|
'css/site.less',
|
|
|
|
];
|
|
|
|
public $js = [
|
|
|
|
'js/site.ts',
|
|
|
|
];
|
|
|
|
public $depends = [
|
|
|
|
'yii\web\YiiAsset',
|
|
|
|
'yii\bootstrap\BootstrapAsset',
|
|
|
|
];
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
When you register such an asset bundle with a view, the [[yii\web\AssetManager|asset manager]] will automatically
|
|
|
|
run the pre-processor tools to convert assets in recognized extended syntax into CSS/JavaScript. When the view
|
|
|
|
finally renders a page, it will include the CSS/JavaScript files in the page, instead of the original assets
|
|
|
|
in extended syntax.
|
|
|
|
|
|
|
|
Yii uses the file name extensions to identify which extended syntax an asset is in. By default it recognizes
|
|
|
|
the following syntax and file name extensions:
|
|
|
|
|
|
|
|
- [LESS](http://lesscss.org/): `.less`
|
|
|
|
- [SCSS](http://sass-lang.com/): `.scss`
|
|
|
|
- [Stylus](http://learnboost.github.io/stylus/): `.styl`
|
|
|
|
- [CoffeeScript](http://coffeescript.org/): `.coffee`
|
|
|
|
- [TypeScript](http://www.typescriptlang.org/): `.ts`
|
|
|
|
|
|
|
|
Yii relies on the installed pre-processor tools to convert assets. For example, to use [LESS](http://lesscss.org/)
|
|
|
|
you should install the `lessc` pre-processor command.
|
|
|
|
|
|
|
|
You can customize the pre-processor commands and the supported extended syntax by configuring
|
|
|
|
[[yii\web\AssetManager::converter]] like the following:
|
|
|
|
|
|
|
|
```php
|
|
|
|
return [
|
|
|
|
'components' => [
|
|
|
|
'assetManager' => [
|
|
|
|
'converter' => [
|
|
|
|
'class' => 'yii\web\AssetConverter',
|
|
|
|
'commands' => [
|
|
|
|
'less' => ['css', 'lessc {from} {to} --no-color'],
|
|
|
|
'ts' => ['js', 'tsc --out {to} {from}'],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
];
|
|
|
|
```
|
|
|
|
|
|
|
|
In the above we specify the supported extended syntax via the [[yii\web\AssetConverter::commands]] property.
|
|
|
|
The array keys are the file extension names (without leading dot), and the array values are the resulting
|
|
|
|
asset file extension names and the commands for performing the asset conversion. The tokens `{from}` and `{to}`
|
|
|
|
in the commands will be replaced with the source asset file paths and the target asset file paths.
|
|
|
|
|
|
|
|
> Info: There are other ways of working with assets in extended syntax, besides the one described above.
|
|
|
|
For example, you can use build tools such as [grunt](http://gruntjs.com/) to monitor and automatically
|
|
|
|
convert assets in extended syntax. In this case, you should list the resulting CSS/JavaScript files in
|
|
|
|
asset bundles rather than the original files.
|
|
|
|
|
|
|
|
|
|
|
|
## Combining and Compressing Assets <a name="combining-compressing-assets"></a>
|
|
|
|
|
|
|
|
A Web page can include many CSS and/or JavaScript files. To reduce the number of HTTP requests and the overall
|
|
|
|
download size of these files, a common practice is to combine and compress multiple CSS/JavaScript files into
|
|
|
|
one or very few files, and then include these compressed files instead of the original ones in the Web pages.
|
|
|
|
|
|
|
|
> Info: Combining and compressing assets is usually needed when an application is in production mode.
|
|
|
|
In development mode, using the original CSS/JavaScript files is often more convenient for debugging purpose.
|
|
|
|
|
|
|
|
In the following, we introduce an approach to combine and compress asset files without the need of modifying
|
|
|
|
your existing application code.
|
|
|
|
|
|
|
|
1. Find out all asset bundles in your application that you plan to combine and compress.
|
|
|
|
2. Divide these bundles into one or a few groups. Note that each bundle can only belong to a single group.
|
|
|
|
3. Combine/compress the CSS files in each group into a single file. Do this similarly for the JavaScript files.
|
|
|
|
4. Define a new asset bundle for each group:
|
|
|
|
* Set the [[yii\web\AssetBundle::css|css]] and [[yii\web\AssetBundle::js|js]] properties to be
|
|
|
|
the combined CSS and JavaScript files, respectively.
|
|
|
|
* Customize the asset bundles in each group by setting their [[yii\web\AssetBundle::css|css]] and
|
|
|
|
[[yii\web\AssetBundle::js|js]] properties to be empty, and setting their [[yii\web\AssetBundle::depends|depends]]
|
|
|
|
property to be the new asset bundle created for the group.
|
|
|
|
|
|
|
|
Using this approach, when you register an asset bundle in a view, it causes the automatic registration of
|
|
|
|
the new asset bundle for the group that the original bundle belongs to. And as a result, the combined/compressed
|
|
|
|
asset files are included in the page, instead of the original ones.
|
|
|
|
|
|
|
|
|
|
|
|
### An Example <a name="example"></a>
|
|
|
|
|
|
|
|
Let's use an example to further explain the above approach.
|
|
|
|
|
|
|
|
Assume your application has two pages X and Y. Page X uses asset bundle A, B and C, while Page Y uses asset bundle B, C and D.
|
|
|
|
|
|
|
|
You have two ways to divide these asset bundles. One is to use a single group to include all asset bundles, the
|
|
|
|
other is to put (A, B, C) in Group X, and (B, C, D) in Group Y. Which one is better? It depends. The first way
|
|
|
|
has the advantage that both pages share the same combined CSS and JavaScript files, which makes HTTP caching
|
|
|
|
more effective. On the other hand, because the single group contains all bundles, the size of the combined CSS and
|
|
|
|
JavaScript files will be bigger and thus increase the initial file transmission time. In this example, we will use
|
|
|
|
the first way, i.e., use a single group to contain all bundles.
|
|
|
|
|
|
|
|
> Info: Dividing asset bundles into groups is not trivial task. It usually requires analysis about the real world
|
|
|
|
traffic data of various assets on different pages. At the beginning, you may start with a single group for simplicity.
|
|
|
|
|
|
|
|
Use existing tools (e.g. [Closure Compiler](https://developers.google.com/closure/compiler/),
|
|
|
|
[YUI Compressor](https://github.com/yui/yuicompressor/)) to combine and compress CSS and JavaScript files in
|
|
|
|
all the bundles. Note that the files should be combined in the order that satisfies the dependencies among the bundles.
|
|
|
|
For example, if Bundle A depends on B which depends on both C and D, then you should list the asset files starting
|
|
|
|
from C and D, followed by B and finally A.
|
|
|
|
|
|
|
|
After combining and compressing, we get one CSS file and one JavaScript file. Assume they are named as
|
|
|
|
`all-xyz.css` and `all-xyz.js`, where `xyz` stands for a timestamp or a hash that is used to make the file name unique
|
|
|
|
to avoid HTTP caching problem.
|
|
|
|
|
|
|
|
We are at the last step now. Configure the [[yii\web\AssetManager|asset manager]] as follows in the application
|
|
|
|
configuration:
|
|
|
|
|
|
|
|
```php
|
|
|
|
return [
|
|
|
|
'components' => [
|
|
|
|
'assetManager' => [
|
|
|
|
'bundles' => [
|
|
|
|
'all' => [
|
|
|
|
'class' => 'yii\web\AssetBundle',
|
|
|
|
'basePath' => '@webroot/assets',
|
|
|
|
'baseUrl' => '@web/assets',
|
|
|
|
'css' => ['all-xyz.css'],
|
|
|
|
'js' => ['all-xyz.js'],
|
|
|
|
],
|
|
|
|
'A' => ['css' => [], 'js' => [], 'depends' => ['all']],
|
|
|
|
'B' => ['css' => [], 'js' => [], 'depends' => ['all']],
|
|
|
|
'C' => ['css' => [], 'js' => [], 'depends' => ['all']],
|
|
|
|
'D' => ['css' => [], 'js' => [], 'depends' => ['all']],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
];
|
|
|
|
```
|
|
|
|
|
|
|
|
As explained in the [Customizing Asset Bundles](#customizing-asset-bundles) subsection, the above configuration
|
|
|
|
changes the default behavior of each bundle. In particular, Bundle A, B, C and D no longer have any asset files.
|
|
|
|
They now all depend on the `all` bundle which contains the combined `all-xyz.css` and `all-xyz.js` files.
|
|
|
|
Consequently, for Page X, instead of including the original source files from Bundle A, B and C, only these
|
|
|
|
two combined files will be included; the same thing happens to Page Y.
|
|
|
|
|
|
|
|
There is one final trick to make the above approach work more smoothly. Instead of directly modifying the
|
|
|
|
application configuration file, you may put the bundle customization array in a separate file and conditionally
|
|
|
|
include this file in the application configuration. For example,
|
|
|
|
|
|
|
|
```php
|
|
|
|
return [
|
|
|
|
'components' => [
|
|
|
|
'assetManager' => [
|
|
|
|
'bundles' => require(__DIR__ . '/' . (YII_ENV_PROD ? 'assets-prod.php' : 'assets-dev.php')),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
];
|
|
|
|
```
|
|
|
|
|
|
|
|
That is, the asset bundle configuration array is saved in `assets-prod.php` for production mode, and
|
|
|
|
`assets-dev.php` for non-production mode.
|
|
|
|
|
|
|
|
|
|
|
|
### Using the `asset` Command <a name="using-asset-command"></a>
|
|
|
|
|
|
|
|
Yii provides a console command named `asset` to automate the approach that we just described.
|
|
|
|
|
|
|
|
To use this command, you should first create a configuration file to describe what asset bundles should
|
|
|
|
be combined and how they should be grouped. You can use the `asset/template` sub-command to generate
|
|
|
|
a template first and then modify it to fit for your needs.
|
|
|
|
|
|
|
|
```
|
|
|
|
yii asset/template assets.php
|
|
|
|
```
|
|
|
|
|
|
|
|
The command generates a file named `assets.php` in the current directory. The content of this file looks like the following:
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Configuration file for the "yii asset" console command.
|
|
|
|
* Note that in the console environment, some path aliases like '@webroot' and '@web' may not exist.
|
|
|
|
* Please define these missing path aliases.
|
|
|
|
*/
|
|
|
|
return [
|
|
|
|
// Adjust command/callback for JavaScript files compressing:
|
|
|
|
'jsCompressor' => 'java -jar compiler.jar --js {from} --js_output_file {to}',
|
|
|
|
// Adjust command/callback for CSS files compressing:
|
|
|
|
'cssCompressor' => 'java -jar yuicompressor.jar --type css {from} -o {to}',
|
|
|
|
// The list of asset bundles to compress:
|
|
|
|
'bundles' => [
|
|
|
|
// 'yii\web\YiiAsset',
|
|
|
|
// 'yii\web\JqueryAsset',
|
|
|
|
],
|
|
|
|
// Asset bundle for compression output:
|
|
|
|
'targets' => [
|
|
|
|
'all' => [
|
|
|
|
'class' => 'yii\web\AssetBundle',
|
|
|
|
'basePath' => '@webroot/assets',
|
|
|
|
'baseUrl' => '@web/assets',
|
|
|
|
'js' => 'js/all-{hash}.js',
|
|
|
|
'css' => 'css/all-{hash}.css',
|
|
|
|
],
|
|
|
|
],
|
|
|
|
// Asset manager configuration:
|
|
|
|
'assetManager' => [
|
|
|
|
],
|
|
|
|
];
|
|
|
|
```
|
|
|
|
|
|
|
|
You should modify this file and specify which bundles you plan to combine in the `bundles` option. In the `targets`
|
|
|
|
option you should specify how the bundles should be divided into groups. You can specify one or multiple groups,
|
|
|
|
as aforementioned.
|
|
|
|
|
|
|
|
> Note: Because the alias `@webroot` and `@web` are not available in the console application, you should
|
|
|
|
explicitly define them in the configuration.
|
|
|
|
|
|
|
|
JavaScript files are combined, compressed and written to `js/all-{hash}.js` where {hash} is replaced with the hash of
|
|
|
|
the resulting file.
|
|
|
|
|
|
|
|
The `jsCompressor` and `cssCompressor` options specify the console commands or PHP callbacks for performing
|
|
|
|
JavaScript and CSS combining/compressing. By default Yii uses [Closure Compiler](https://developers.google.com/closure/compiler/)
|
|
|
|
for combining JavaScript files and [YUI Compressor](https://github.com/yui/yuicompressor/) for combining CSS files.
|
|
|
|
You should install tools manually or adjust these options to use your favorite tools.
|
|
|
|
|
|
|
|
|
|
|
|
With the configuration file, you can run the `asset` command to combine and compress the asset files
|
|
|
|
and then generate a new asset bundle configuration file `assets-prod.php`:
|
|
|
|
|
|
|
|
```
|
|
|
|
yii asset assets.php config/assets-prod.php
|
|
|
|
```
|
|
|
|
|
|
|
|
The generated configuration file can be included in the application configuration, like described in
|
|
|
|
the last subsection.
|
|
|
|
|
|
|
|
|
|
|
|
> Info: Using the `asset` command is not the only option to automate the asset combining and compressing process.
|
|
|
|
You can use the excellent task runner tool [grunt](http://gruntjs.com/) to achieve the same goal.
|