Commit 4d6ebae3 by Qiang Xue

finished asset.

parent e89a2954
Assets
======
> Note: This section is under writing.
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 folders and are directly served by Web servers.
An asset in Yii is a file that may be referenced or linked in a Web page. It can be a CSS file, a JavaScript file,
an image or video file, etc. For simple Web applications, assets may be managed manually - you place them in a Web folder
and reference them using their URLs in your Web pages. However, if an application is complicated, or if it uses
many third-party extensions, manual management of assets can soon become a headache. For example, how will you ensure
one JavaScript file is always included before another and the same JavaScript file is not included twice?
How will you handle asset files required by an extension which you do not want to dig into its internals?
How will you combine and compress multiple CSS/JavaScript files into a single one when you deploy the application
to production? In this section, we will describe the asset management capability offered by Yii to help you alleviate
all these problems.
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>
Assets are organized in *bundles*. An asset bundle represents a collection of asset files located
under a single directory. It lists which CSS and JavaScript files are in this collection and should be included
in a page where the bundle is used.
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>
## Defining Asset Bundles <a name="defining-asset-bundles"></a>
An asset bundle is defined in terms of a PHP class extending from [[yii\web\AssetBundle]].
In this class, you use certain class properties to specify where the asset files are located, what CSS/JavaScript
files the bundle contains, and so on. The class should be namespaced and autoloadable. Its name is used
as the name of the asset bundle.
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):
......@@ -53,11 +50,10 @@ class AppAsset extends AssetBundle
}
```
The `AppAsset` class basically specifies that the asset files are located under the `@webroot` directory which
is corresponding to the URL `@web`. The bundle only contains an asset file named `css/site.css`. The bundle
depends on two other bundles: `yii\web\YiiAsset` and `yii\bootstrap\BootstrapAsset`.
The following list explains the possible properties that you can set in an asset bundle class:
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
......@@ -94,88 +90,229 @@ The following list explains the possible properties that you can set in an asset
This is only used if you specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property.
#### Asset Locations <a name="asset-locations"></a>
### 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 for source assets to be Web accessible, they should be published and turned in *published assets*.
In order to use source assets in a page, they should be copied to a Web folder 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 folder 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.
For assets that directly belong to an application, it is recommended that you place them in a Web folder
to avoid the unnecessary asset publishing process. This is why `AppAsset` specifies [[yii\web\AssetBundle::basePath|basePath]]
without [[yii\web\AssetBundle::sourcePath|sourcePath]].
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 folder 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 assets belonging to an [extension](structure-extensions.md), as they are in a folder that is not Web accessible,
you have to specify the [[yii\web\AssetBundle::sourcePath|sourcePath]] property when declaring the corresponding
asset bundle.
For [extensions](structure-extensions.md), because their assets are located together with their source code
in folders 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 folder is used by default by the [[yii\web\AssetManager|asset manager]] to keep the asset files
This folder 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 folder are considered temporarily and may be subject
to removal.
#### Asset Dependencies <a name="asset-dependencies"></a>
### 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>
When you include multiple CSS or JavaScript files on a Web page, they have to follow certain orders to avoid
unexpected overriding. 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 is included.
We call such ordering the dependencies among assets.
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.
Asset dependencies are mainly specified through the [[yii\web\AssetBundle::depends]] property of asset bundles.
In the `AppAsset` example, the asset bundle depends on two other asset bundles: `yii\web\YiiAsset` and
`yii\bootstrap\BootstrapAsset`. And for the jQuery UI example just described, the asset bundle is declared as follows:
> 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
class JuiAsset extends AssetBundle
{
public $sourcePath = '@bower/jquery-ui';
public $js = [
'jquery-ui.js',
];
public $css = [
'themes/smoothness/jquery-ui.css',
];
public $depends = [
'yii\web\JqueryAsset',
];
}
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 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 folder 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) like the following in a view template:
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);
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 folder inaccessible through the Web, it will be published to a Web folder.
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',
],
],
],
];
```
where `$this` refers to the [[yii\web\View|view]] object. If you are registering an asset bundle in a PHP class,
you should provide the needed the view object. For example, to register an asset bundle in
a [widget](structure-widgets.md) class, you can obtain the view object by `$this->view`.
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 [[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`.
When an asset bundle is registered, behind the scene Yii will register all its dependent asset bundles. And
when a page is being rendered, `<link>` and `<script>` tags will be generated in the page for the CSS and
JavaScript files in every registered asset bundle. During this process, if an asset bundle is not in
a Web accessible folder, it will be published first.
> 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>
### Asset Publishing <a name="asset-publishing"></a>
When an asset file is located in a folder that is not Web accessible, it should be copied to a Web accessible
folder before being referenced or linked in a Web page. This process is called *asset publishing*, and is done
As aforementioned, if an asset bundle is located in a folder that is not Web accessible, its assets will be copied
to a Web folder 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]].
### Enabling symlinks
By default, assets are published to the folder `@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::basePath|basePath]] properties.
Asset manager is able to use symlinks instead of copying files. It is turned off by default since symlinks are often
disabled on shared hosting. If your hosting environment supports symlinks you certainly should enable the feature via
application config:
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 [
......@@ -188,135 +325,218 @@ return [
];
```
There are two main benefits in enabling it. First it is faster since no copying is required and second is that assets
will always be up to date with source files.
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.
#### Language-specific asset bundle
## Commonly Used Asset Bundles <a name="common-asset-bundles"></a>
If you need to define an asset bundle that includes JavaScript file depending on the language you can do it the
following way:
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 LanguageAsset extends AssetBundle
class AppAsset extends AssetBundle
{
public static $language;
public $sourcePath = '@app/assets/language';
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = [
'css/site.less',
];
public $js = [
'js/site.ts',
];
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap\BootstrapAsset',
];
public function init()
{
parent::init();
$language = self::$language ? self::$language : Yii::$app->language;
$this->js[] = 'language-' . $language . '.js';
}
}
```
In order to set language use the following code when registering an asset bundle in a view:
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, o 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
LanguageAsset::$language = $language;
LanguageAsset::register($this);
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.
#### Setting special options <a name="setting-special-options"></a>
## Combining and Compressing Assets <a name="combining-compressing-assets"></a>
Asset bundles allow setting specific options for the files to be published.
This can be done by configuring the [[yii\web\AssetBundle::$jsOptions|$jsOptions]],
[[yii\web\AssetBundle::$cssOptions|$cssOptions]] or [[yii\web\AssetBundle::$publishOptions|$publishOptions]]
property of the asset bundle.
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.
Some of these options are described in the following:
> 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.
- For setting conditional comments for your CSS files you can set the following option:
In the following, we introduce an approach to combine and compress asset files without the need of modifying
your existing application code.
```php
public $cssOptions = ['condition' => 'lte IE9'];
```
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.
This will result in a link tag generated as follows: `<!--[if lte IE9]><link .../><![endif]-->`.
You can only define one condition per asset bundle, if you have multiple files with different conditions,
you have to define multiple assets bundles.
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.
- For javascipt files you can define the position where they should be added in the HTML.
You can choose one of the following positions:
- [[yii\web\View::POS_HEAD]]: in the head section
- [[yii\web\View::POS_BEGIN]]: at the beginning of the body section
- [[yii\web\View::POS_END]]: at the end of the body section. This is the default value.
### An Example <a name="example"></a>
Example for putting all javascript files to the end of the body.
Let's use an example to further explain the above approach.
```php
public $jsOptions = ['position' => \yii\web\View::POS_END];
```
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.
This option is also reflected when resolving dependencies.
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.
- For further javascript options, see [[yii\helpers\Html::jsFile()]].
> 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.
#### Overriding asset bundles
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.
Sometimes you need to override some asset bundles application wide. A good example is loading jQuery from CDN instead
of your own server. In order to do it we need to configure `assetManager` application component via config file. In case
of basic application it is `config/web.php`:
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' => [
'yii\web\JqueryAsset' => [
'sourcePath' => null,
'js' => ['//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js']
'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']],
],
],
],
];
```
In the above we're adding asset bundle definitions to the [[yii\web\AssetManager::bundles|bundles]] property of asset manager. Keys are fully
qualified class names to asset bundle classes we want to override while values are key-value arrays of class properties
and corresponding values to set.
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.
Setting `sourcePath` to `null` tells asset manager not to copy anything while `js` overrides local files with a link
to CDN.
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,
> Tip: You may also use this procedure to configure different scripts dependent on the environment. For example
> use minified files in production and normal files in development:
>
> ```php
'yii\web\JqueryAsset' => [
'js' => [
YII_ENV_DEV ? 'jquery.js' : 'jquery.min.js'
]
],
```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.
Compressing and combining assets
--------------------------------
### Using the `asset` Command <a name="using-asset-command"></a>
To improve application performance you can compress and then combine several CSS or JS files into lesser number of files
therefore reducing number of HTTP requests and overall download size needed to load a web page. Yii provides a console
command that allows you to do both.
Yii provides a console command named `asset` to automate the approach that we just described.
### Preparing configuration
In order to use `asset` command you should prepare a configuration first. A template for it can be generated using
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 /path/to/myapp/config.php
yii asset/template assets.php
```
The template itself looks like the following:
The command generates a file named `assets.php` in the current directory. The content of this file looks like the following:
```php
<?php
......@@ -352,127 +572,29 @@ return [
];
```
In the above keys are `properties` of `AssetController`. `bundles` list contains bundles that should be compressed. These are typically what's used by application.
`targets` contains a list of bundles that define how resulting files will be written. In our case we're writing
everything to `path/to/web` that can be accessed like `http://example.com/` i.e. it is website root directory.
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: in the console environment some path aliases like '@webroot' and '@web' may not exist,
so corresponding paths inside the configuration should be specified directly.
> 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.
`jsCompressor` and `cssCompressor` are console commands or PHP callbacks, which should perform JavaScript and CSS files
compression correspondingly. You should adjust these values according to your environment.
By default Yii relies on [Closure Compiler](https://developers.google.com/closure/compiler/) for JavaScript file compression,
and on [YUI Compressor](https://github.com/yui/yuicompressor/). You should install this utilities manually, if you wish to use them.
### Providing compression tools
The command relies on external compression tools that are not bundled with Yii so you need to provide CSS and JS
compressors which are correspondingly specified via `cssCompressor` and `jsCompression` properties. If compressor is
specified as a string it is treated as a shell command template which should contain two placeholders: `{from}` that
is replaced by source file name and `{to}` that is replaced by output file name. Another way to specify compressor is
to use any valid PHP callback.
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.
By default for JavaScript compression Yii tries to use
[Google Closure compiler](https://developers.google.com/closure/compiler/) that is expected to be in a file named
`compiler.jar`.
For CSS compression Yii assumes that [YUI Compressor](https://github.com/yui/yuicompressor/) is looked up in a file
named `yuicompressor.jar`.
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`:
In order to compress both JavaScript and CSS, you need to download both tools and place them under the directory
containing your `yii` console bootstrap file. You also need to install JRE in order to run these tools.
You may customize the compression commands (e.g. changing the location of the jar files) in the `config.php` file
like the following,
```php
return [
'cssCompressor' => 'java -jar path.to.file\yuicompressor.jar --type css {from} -o {to}',
'jsCompressor' => 'java -jar path.to.file\compiler.jar --js {from} --js_output_file {to}',
];
```
where `{from}` and `{to}` are tokens that will be replaced with the actual source and target file paths, respectively,
when the `asset` command is compressing every file.
### Performing compression
After configuration is adjusted you can run the `compress` action, using created config:
```
yii asset /path/to/myapp/config.php /path/to/myapp/config/assets_compressed.php
```
Now processing takes some time and finally finished. You need to adjust your web application config to use compressed
assets file like the following:
```php
'components' => [
// ...
'assetManager' => [
'bundles' => require '/path/to/myapp/config/assets_compressed.php',
],
],
yii asset assets.php config/assets-prod.php
```
Using asset converter
---------------------
Instead of using CSS and JavaScript directly often developers are using their improved versions such as LESS or SCSS
for CSS or Microsoft TypeScript for JavaScript. Using these with Yii is easy.
First of all, corresponding compression tools should be installed and should be available from where `yii` console
bootstrap file is. The following lists file extensions and their corresponding conversion tool names that Yii converter
recognizes:
- LESS: `less` - `lessc`
- SCSS: `scss`, `sass` - `sass`
- Stylus: `styl` - `stylus`
- CoffeeScript: `coffee` - `coffee`
- TypeScript: `ts` - `tsc`
So if the corresponding tool is installed you can specify any of these in asset bundle:
```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',
];
}
```
In order to adjust conversion tool call parameters or add new ones you can use application config:
```php
// ...
'components' => [
'assetManager' => [
'converter' => [
'class' => 'yii\web\AssetConverter',
'commands' => [
'less' => ['css', 'lessc {from} {to} --no-color'],
'ts' => ['js', 'tsc --out {to} {from}'],
],
],
],
],
```
The generated configuration file can be included in the application configuration, like described in
the last subsection.
In the above we've left two types of extra file extensions. First one is `less` that can be specified in `css` part
of an asset bundle. Conversion is performed via running `lessc {from} {to} --no-color` where `{from}` is replaced with
LESS file path while `{to}` is replaced with target CSS file path. Second one is `ts` that can be specified in `js` part
of an asset bundle. The command that is run during conversion is in the same format that is used for `less`.
......@@ -179,11 +179,33 @@ can know which extensions are installed (the information can be accessed via [[y
#### Dependencies <a name="dependencies"></a>
Your extension depends on Yii (of course). So you should list it in the `require` entry in `composer.json`.
Your extension depends on Yii (of course). So you should list it (`yiisoft/yii2`) in the `require` entry in `composer.json`.
If your extension also depends on other extensions or third-party libraries, you should list them as well.
Make sure you also list appropriate version constraints (e.g. `1.*`, `@stable`) for each dependency. Use stable
Make sure you also list appropriate version constraints (e.g. `1.*`, `@stable`) for each dependent package. Use stable
dependencies when your extension is released in a stable version.
Most JavaScript/CSS packages are managed using [Bower](http://bower.io/) and/or [NPM](https://www.npmjs.org/),
instead of Composer. Yii uses the [Composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin)
to enable managing these kinds of packages through Composer. If your extension depends on a Bower package, you can
simply list the dependency in `composer.json` like the following:
```json
{
// package dependencies
"require": {
"bower-asset/jquery": ">=1.11.*"
}
}
```
The above code states that the extension depends on the `jquery` Bower package. In general, you can use
`bower-asset/PackageName` to refer to a Bower package in `composer.json`, and use `npm-asset/PackageName`
to refer to a NPM package. When Composer installs a Bower or NPM package, by default the package content will be
installed under the `@vendor/bower/PackageName` and `@vendor/npm/Packages` directories, respectively.
These two directories can also be referred to using the shorter aliases `@bower/PackageName` and `@npm/PackageName`.
For more details about asset management, please refer to the [Assets](structure-assets.md#bower-npm-assets) section.
#### Class Autoloading <a name="class-autoloading"></a>
......@@ -298,9 +320,10 @@ two choices to make the asset files directly accessible via Web:
copy the files listed in the asset bundle to a Web-accessible folder.
We recommend you use the second approach so that your extension can be more easily used by other people.
Please refer to the [Assets] section for more details about how to work with assets in general.
### Internationalization and Localization <a name="i18n-l10n"></a>
#### Internationalization and Localization <a name="i18n-l10n"></a>
Your extension may be used by applications supporting different languages! Therefore, if your extension displays
content to end users, you should try to [internationalize and localize](tutorial-i18n.md) it. In particular,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment