structure-assets.md 14.1 KB
Newer Older
1 2 3
Managing assets
===============

4
> Note: This section is under development.
Qiang Xue committed
5

6
An asset in Yii is a file that is included into the page. It could be CSS, JavaScript or
Carsten Brandt committed
7 8 9
any other file. The framework provides many ways to work with assets from basics such as adding `<script src="...">` tags
for a file which is covered by the [View section](view.md), to advanced usage such as publishing files that are not
under the webservers document root, resolving JavaScript dependencies or minifying CSS, which we will cover in the following.
10 11


Carsten Brandt committed
12 13
Declaring asset bundles
-----------------------
14

Carsten Brandt committed
15 16
In order to define a set of assets the belong together and should be used on the website you declare a class called
an "asset bundle". The bundle defines a set of asset files and their dependencies on other asset bundles.
17

Carsten Brandt committed
18 19 20 21 22 23 24 25
Asset files can be located under the webservers accessable directory but also hidden inside of application or vendor
directories. If the latter, the asset bundle will care for publishing them to a directory accessible by the webserver
so they can be included in the website. This feature is useful for extensions so that they can ship all content in one
directory and make installation easier for you.

To define an asset you create a class extending from [[yii\web\AssetBundle]] and set the properties according to your needs.
Here you can see an example asset definition which is part of the basic application template, the
`AppAsset` asset bundle class. It defines assets required application wide:
26 27

```php
28 29 30 31
<?php

use yii\web\AssetBundle as AssetBundle;

32 33
class AppAsset extends AssetBundle
{
34 35 36 37 38 39 40 41 42 43 44
    public $basePath = '@webroot';
    public $baseUrl = '@web';
    public $css = [
        'css/site.css',
    ];
    public $js = [
    ];
    public $depends = [
        'yii\web\YiiAsset',
        'yii\bootstrap\BootstrapAsset',
    ];
45 46 47 48
}
```

In the above `$basePath` specifies web-accessible directory assets are served from. It is a base for relative
Carsten Brandt committed
49
`$css` and `$js` paths i.e. `@webroot/css/site.css` for `css/site.css`. Here `@webroot` is an [alias][] that points to
50 51 52
application's `web` directory.

`$baseUrl` is used to specify base URL for the same relative `$css` and `$js` i.e. `@web/css/site.css` where `@web`
Carsten Brandt committed
53
is an [alias][] that corresponds to your website base URL such as `http://example.com/`.
54

Carsten Brandt committed
55
In case you have asset files under a non web accessible directory, that is the case for any extension, you need
56 57
to specify `$sourcePath` instead of `$basePath` and `$baseUrl`. **All files** from the source path will be copied
or symlinked to the `web/assets` directory of your application prior to being registered.
Carsten Brandt committed
58
In this case `$basePath` and `$baseUrl` are generated automatically at the time of publishing the asset bundle.
59 60
This is the way to work with assets when you want to publish the whole directory no matter what's in be it images,
webfonts etc.
61

62 63 64

> **Note:** do not use the `web/assets` path to put your own files in it. It is meant to be used only for asset publishing.
> When you create files that are already in web accessable directory put them in folders like `web/css` or `web/js`.
65

66
Dependencies on other asset bundles are specified via `$depends` property. It is an array that contains fully qualified
Carsten Brandt committed
67 68 69
class names of bundle classes that should be published in order for this bundle to work properly.
Javascript and CSS files for `AppAsset` are added to the header after the files of [[yii\web\YiiAsset]] and
[[yii\bootstrap\BootstrapAsset]] in this example.
70

Carsten Brandt committed
71
Here [[yii\web\YiiAsset]] adds Yii's JavaScript library while [[yii\bootstrap\BootstrapAsset]] includes
72 73 74
[Bootstrap](http://getbootstrap.com) frontend framework.

Asset bundles are regular classes so if you need to define another one, just create alike class with unique name. This
75
class can be placed anywhere but the convention for it is to be under `assets` directory of the application.
76

77
Additionally you may specify `$jsOptions`, `$cssOptions` and `$publishOptions` that will be passed to
78
[[yii\web\View::registerJsFile()]], [[yii\web\View::registerCssFile()]] and [[yii\web\AssetManager::publish()]]
79 80
respectively during registering and publising an asset.

Carsten Brandt committed
81 82 83
[alias]: basics.md#path-aliases "Yii Path alias"


Alexander Makarov committed
84 85 86 87 88 89 90 91
### Language-specific asset bundle

If you need to define an asset bundle that includes JavaScript file depending on the language you can do it the
following way:

```php
class LanguageAsset extends AssetBundle
{
92 93 94 95 96 97 98 99 100 101 102
    public $language;
    public $sourcePath = '@app/assets/language';
    public $js = [
    ];

    public function registerAssetFiles($view)
    {
        $language = $this->language ? $this->language : Yii::$app->language;
        $this->js[] = 'language-' . $language . '.js';
        parent::registerAssetFiles($view);
    }
Alexander Makarov committed
103 104 105
}
```

106 107 108 109 110 111
In order to set language use the following code when registering an asset bundle in a view:

```php
LanguageAsset::register($this)->language = $language;
```

Carsten Brandt committed
112

113 114 115
Registering asset bundle
------------------------

Carsten Brandt committed
116 117 118 119
Asset bundle classes are typically registered in view files or [widgets](view.md#widgets) that depend on the css or
javascript files for providing its functionality. An exception to this is the `AppAsset` class defined above which is
added in the applications main layout file to be registered on any page of the application.
Registering an asset bundle is as simple as calling the [[yii\web\AssetBundle::register()|register()]] method:
120 121 122 123 124 125 126

```php
use app\assets\AppAsset;
AppAsset::register($this);
```

Since we're in a view context `$this` refers to `View` class.
Carsten Brandt committed
127 128 129 130 131 132
To register an asset inside of a widget, the view instance is available as `$this->view`:

```php
AppAsset::register($this->view);
```

133 134 135 136
> Note: If there is a need to modify third party asset bundles it is recommended to create your own bundles depending
  on third party ones and use CSS and JavaScript features to modify behavior instead of editing files directly or
  copying them over.

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160

Overriding asset bundles
------------------------

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`:

```php
return [
    // ...
    'components' => [
        'assetManager' => [
            'bundles' => [
                'yii\web\JqueryAsset' => [
                     'sourcePath' => null,
                     'js' => ['//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js']
                ],
            ],
        ],
    ],
];
```

Carsten Brandt committed
161 162
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
163 164 165 166 167
and corresponding values to set.

Setting `sourcePath` to `null` tells asset manager not to copy anything while `js` overrides local files with a link
to CDN.

Carsten Brandt committed
168

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
Enabling symlinks
-----------------

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:

```php
return [
    // ...
    'components' => [
        'assetManager' => [
            'linkAssets' => true,
        ],
    ],
];
```

There are two main benefits in enabling it. First it is faster since no copying is required and second is that assets
188 189
will always be up to date with source files.

Carsten Brandt committed
190

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
Compressing and combining assets
--------------------------------

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.

### Preparing configuration

In order to use `asset` command you should prepare a configuration first. A template for it can be generated using

```
yii asset/template /path/to/myapp/config.php
```

The template itself 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 [
216 217 218 219
    // 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}',
220 221 222 223 224 225 226 227 228 229
    // The list of asset bundles to compress:
    'bundles' => [
        // 'yii\web\YiiAsset',
        // 'yii\web\JqueryAsset',
    ],
    // Asset bundle for compression output:
    'targets' => [
        'app\config\AllAsset' => [
            'basePath' => 'path/to/web',
            'baseUrl' => '',
230 231
            'js' => 'js/all-{hash}.js',
            'css' => 'css/all-{hash}.css',
232 233 234 235 236 237 238
        ],
    ],
    // Asset manager configuration:
    'assetManager' => [
        'basePath' => __DIR__,
        'baseUrl' => '',
    ],
239 240 241 242 243 244 245 246 247 248
];
```

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.

> 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.

249 250
JavaScript files are combined, compressed and written to `js/all-{hash}.js` where {hash} is replaced with the hash of
the resulting file.
251

252 253 254 255 256
`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.

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
### 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.

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`.

Qiang Xue committed
272 273 274 275 276
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,
277

278 279
```php
return [
280 281
       '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}',
282 283
];
```
Qiang Xue committed
284 285 286

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.
287 288


289 290 291 292 293 294 295 296 297 298 299 300 301
### 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' => [
302 303 304 305
    // ...
    'assetManager' => [
        'bundles' => require '/path/to/myapp/config/assets_compressed.php',
    ],
306 307 308 309 310 311 312 313 314
],
```

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.

315
First of all, corresponding compression tools should be installed and should be available from where `yii` console
316 317 318 319 320 321 322 323 324 325 326 327 328 329
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
{
330 331 332 333 334 335 336 337 338 339 340 341
    public $basePath = '@webroot';
    public $baseUrl = '@web';
    public $css = [
        'css/site.less',
    ];
    public $js = [
        'js/site.ts',
    ];
    public $depends = [
        'yii\web\YiiAsset',
        'yii\bootstrap\BootstrapAsset',
    ];
342 343 344 345 346 347 348 349
}
```

In order to adjust conversion tool call parameters or add new ones you can use application config:

```php
// ...
'components' => [
350 351 352 353 354 355 356 357 358
    'assetManager' => [
        'converter' => [
            'class' => 'yii\web\AssetConverter',
            'commands' => [
                'less' => ['css', 'lessc {from} {to} --no-color'],
                'ts' => ['js', 'tsc --out {to} {from}'],
            ],
        ],
    ],
359 360 361 362 363 364
],
```

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
365
of an asset bundle. The command that is run during conversion is in the same format that is used for `less`.