structure-assets.md 33.3 KB
Newer Older
larnu committed
1 2 3
Assets
======

4
Un asset en Yii es un archivo al que se puede hacer referencia en una página Web. Puede ser un archivo CSS, un archivo
5
JavaScript, una imagen o un archivo de video, etc. Los assets se encuentran en los directorios públicos de la web y se
larnu committed
6 7
sirven directamente por los servidores Web.

8 9 10
A menudo es preferible gestionar los assets mediante programación. Por ejemplo, cuando se usa el widget
[[yii\jui\DatePicker]] en una página, éste incluirá automáticamente los archivos CSS y JavaScript requeridos, en vez
de tener que buscar los archivos e incluirlos manualmente. Y cuando se actualice el widget a una nueva versión, ésta
larnu committed
11 12 13 14 15
usará de forma automática la nueva versión de los archivos asset.
En este tutorial, se describirá la poderosa capacidad que proporciona la gestión de assets en Yii.

## Asset Bundles <a name="asset-bundles"></a>

16 17
Yii gestiona los assets en unidades de *asset bundle*. Un asset bundle es simplemente un conjunto de assets
localizados en un directorio. Cuando se registra un asset bundle en una [vista](structure-views.md), éste incluirá los
larnu committed
18 19 20 21
archivos CSS y JavaScript del bundle en la página Web renderizada.

## Definición de Asset Bundles <a name="defining-asset-bundles"></a>

22 23 24
Los asset bundles son descritos como clases PHP que extienden a [[yii\web\AssetBundle]]. El nombre del bundle es
simplemente su correspondiente nombre de la classe PHP que debe ser [autocargable](concept-autoloading.md). En una
clase asset bundle, lo más habitual es especificar donde se encuentran los archivos asset, que archivos CSS y
25
JavaScript contiene el bundle, y como depende este bundle de otros bundles.
larnu committed
26

27
El siguiente código define el asset bundle principal que se usa en
larnu committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
[la plantilla de aplicación básica](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',
    ];
}
```

53 54 55
La anterior clase `AppAsset` especifica que los archivos asset se encuentran en el directorio `@webroot` que
corresponde a la URL `@web`; el bundle contiene un único archivo CSS `css/site.css` y ningún archivo JavaScript;
el bundle depende de otros dos bundles: [[yii\web\YiiAsset]] y [[yii\bootstrap\BootstrapAsset]].
larnu committed
56 57
A continuación se explicarán más detalladamente las propiedades del [[yii\web\AssetBundle]]:

58
* [[yii\web\AssetBundle::sourcePath|sourcePath]]: especifica el directorio raíz que contiene los archivos asset en el
59
  bundle.  Si no, se deben especificar las propiedades [[yii\web\AssetBundle::basePath|basePath]] y
larnu committed
60
  [[yii\web\AssetBundle::baseUrl|baseUrl]], en su lugar. Se pueden usar [alias de ruta](concept-aliases.md).
61 62
* [[yii\web\AssetBundle::basePath|basePath]]: especifica el directorio Web público que contiene los archivos assets de
  este bundle. Cuando se especifica la propiedad [[yii\web\AssetBundle::sourcePath|sourcePath]], el [gestor de
63
  assets](#asset-manager) publicará los assets de este bundle en un directorio  Web público  y sobrescribirá la
64
  propiedad en consecuencia. Se debe establecer esta propiedad si los archivos asset ya se encuentran en un directorio
65
  Web público y no necesitan ser publicados. Se pueden usar [alias de ruta](concept-aliases.md).
larnu committed
66
* [[yii\web\AssetBundle::baseUrl|baseUrl]]: especifica la URL correspondiente al directorio
67 68
  [[yii\web\AssetBundle::basePath|basePath]]. Como en [yii\web\AssetBundle::basePath|basePath]], si se especifica la
  propiedad [[yii\web\AssetBundle::sourcePath|sourcePath]], el [gestor de assets](#asset-manager) publicara los assets
larnu committed
69
  y sobrescribirá esta propiedad en consecuencia. Se pueden usar [alias de ruta](concept-aliases.md).
70
* [[yii\web\AssetBundle::js|js]]: un array lista los archivos JavaScript que contiene este bundle. Tenga en cuenta que
71
  solo deben usarse las barras invertidas "/" como separadores de directorios. Cada archivo Javascript se puede
larnu committed
72
  especificar en uno de los siguientes formatos:
73 74
    - una ruta relativa que represente un archivo local JavaScript (ej. `js/main.js`). La ruta actual del fichero
      se puede determinar anteponiendo [[yii\web\AssetManager::basePath]] a la ruta relativa, y la URL actual de un
larnu committed
75
      archivo puede ser determinada anteponiendo [[yii\web\AssetManager::baseUrl]] a la ruta relativa.
76
    - una URL absoluta que represente un archivo JavaScript externo. Por ejemplo,
77
    `http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js` o
larnu committed
78
    `//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js`.
79
* [[yii\web\AssetBundle::css|css]]: un array que lista los archivos CSS que contiene este bundle. El formato de este
larnu committed
80 81 82
  array es el mismo que el de [[yii\web\AssetBundle::js|js]].
* [[yii\web\AssetBundle::depends|depends]]: un array que lista los nombres de los asset bundles de los que depende este
  asset bundle (para explicarlo brevemente).
83
* [[yii\web\AssetBundle::jsOptions|jsOptions]]: especifica las opciones que se enviarán al método
larnu committed
84
  [[yii\web\View::registerJsFile()]] cuando se le llame para registrar *todos* los archivos JavaScript de este bundle.
85
* [[yii\web\AssetBundle::cssOptions|cssOptions]]: especifica las opciones que se enviarán al método
larnu committed
86
  [[yii\web\View::registerCssFile()]] cuando se le llame para registrar *todos* los archivos CSS de este bundle.
87
* [[yii\web\AssetBundle::publishOptions|publishOptions]]: especifica las opciones que se enviarán al método
88
  [[yii\web\AssetManager::publish()]] cuando se le llame para publicar los archivos de los assets fuente a un
larnu committed
89 90 91 92 93 94 95
  directorio Web.
Solo se usa si se especifica la propiedad [[yii\web\AssetBundle::sourcePath|sourcePath]].

### Ubicación de los Assets <a name="asset-locations"></a>

Según la localización de los assets, se pueden clasificar como:

96 97
* assets fuente (source assets): los assets se encuentran junto con el código fuente PHP, al que no se puede acceder
  directamente a través de la Web. Para usar los assets fuente en una página, deben ser copiados en un directorio
98
  público y transformados en los llamados assets publicados. El proceso se llama *publicación de assets* que será
larnu committed
99
  descrito a continuación.
100
* assets publicados (published assets): los archivos assets se encuentran en el directorio Web y son accesibles vía Web.
larnu committed
101 102
* assets externos (external assets): los archivos assets se encuentran en un servidor Web diferente al de la aplicación.

103 104 105 106
Cuando se define una clase asset bundle, si se especifica la propiedad [[yii\web\AssetBundle::sourcePath|sourcePath]],
significa que cualquier asset listado que use rutas relativas será considerado como un asset fuente. Si no se
especifica la propiedad, significa que los assets son assets publicados (se deben especificar
[[yii\web\AssetBundle::basePath|basePath]] y
larnu committed
107 108
[[yii\web\AssetBundle::baseUrl|baseUrl]] para hacerle saber a Yii dónde se encuentran.)

109 110
Se recomienda ubicar los assets que correspondan a la aplicación en un directorio Web para evitar publicaciones de
assets innecesarias. Por esto en el anterior ejemplo `AppAsset` especifica [[yii\web\AssetBundle::basePath|basePath]]
larnu committed
111 112
en vez de [[yii\web\AssetBundle::sourcePath|sourcePath]].

113 114
Para las [extensiones](structure-extensions.md), por el hecho de que sus assets se encuentran junto con el código
fuente, en directorios que no son accesibles para la Web, se tiene que especificar la propiedad
larnu committed
115 116
[[yii\web\AssetBundle::sourcePath|sourcePath]] cuando se definan clases asset bundle para ellas.

117 118
> Nota: No se debe usar `@webroot/assets` como [yii\web\AssetBundle::sourcePath|source path]]. Este directorio se usa
  por defecto por el [[yii\web\AssetManager|asset manager]] para guardar los archivos asset publicados temporalmente y
larnu committed
119 120 121 122
  pueden ser eliminados.

### Dependencias de los Asset <a name="asset-dependencies"></a>

123 124 125
Cuando se incluyen múltiples archivos CSS o JavaScript en una página Web, tienen que cumplir ciertas órdenes para
evitar problemas de sobrescritura. Por ejemplo, si se usa un widget jQuery UI en una página Web, tenemos que
asegurarnos de que el archivo JavaScript jQuery se incluya antes que el archivo JavaScript jQuery UI. A esto se le
larnu committed
126 127
llama ordenar las dependencias entre archivos.

128 129 130
Las dependencias de los assets se especifican principalmente a través de la propiedad [[yii\AssetBundle::depends]].
En el ejemplo `AppAsset`, el asset bundle depende de otros dos asset bundles [[yii\web\YiiAsset]] y
[[yii\bootstrap\BootstrapAsset]], que significa que los archivos CSS y JavaScript en `AppAsset` se incluirán *después*
larnu committed
131 132
que los archivos de los dos bundles dependientes.

133
Las dependencias son transitivas. Esto significa, que si un bundle A depende de un bundle B que depende de C, A
larnu committed
134 135 136 137
dependerá de C, también.

### Opciones de los Assets <a name="asset-options"></a>

138 139
Se pueden especificar las propiedades [[yii\web\AssetBundle::cssOptions|cssOptions]] y
[[yii\web\AssetBundle::jsOptions|jsOptions]] para personalizar la forma en que los archivos CSS y JavaScript serán
140
incluidos en una página. Los valores de estas propiedades serán enviadas a los métodos
141
[[yii\web\View::registerCssFile()]] y [[yii\web\View::registerJsFile()]], respectivamente cuando las
larnu committed
142 143
[vistas](structure-views.md) los llamen para incluir los archivos CSS y JavaScript.

144 145
> Nota: Las opciones que se especifican en una clase bundle se aplican a *todos* los archivos CSS/JavaScript de un
  bundle. Si se quiere usar diferentes opciones para diferentes archivos, se deben crear assets bundles separados y
larnu committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
  usar un conjunto de opciones para cada bundle.

Por ejemplo, para incluir una archivo CSS condicionalmente para navegadores que como IE9 o anteriores, se puede usar la
 siguiente opción:

```php
public $cssOptions = ['condition' => 'lte IE9'];
```

Esto provoca que un archivo CSS dentro de un bundle sea incluido usando los siguientes tags HTML:

```html
<!--[if lte IE9]>
<link rel="stylesheet" href="path/to/foo.css">
<![endif]-->
```

Para envolver el tag del enlace con `<noscript>` se puede usar el siguiente código:

```php
public $cssOptions = ['noscript' => true];
```

Para incluir un archivo JavaScript en la sección cabecera (head) de una página (por defecto, los archivos JavaScript se
 incluyen al final de la sección cuerpo(body)), se puede usar el siguiente código:

```php
public $jsOptions = ['position' => \yii\web\View::POS_HEAD];
```

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
Por defecto, cuando un asset bundle está siendo publicado, todos los contenidos del directorio especificado por [[yii\web\AssetBundle::sourcePath]]
serán publicados. Puedes personalizar este comportamiento configurando la propiedad [[yii\web\AssetBundle::publishOptions|publishOptions]]. Por
ejemplo, públicar solo uno o unos pocos subdirectorios de [[yii\web\AssetBundle::sourcePath]], puedes hacerlo de la siguiente manera en la clase
asset bundle:

```php
<?php
namespace app\assets;

use yii\web\AssetBundle;

class FontAwesomeAsset extends AssetBundle
{
    public $sourcePath = '@bower/font-awesome';
    public $css = [
        'css/font-awesome.min.css',
    ];

    public function init()
    {
        parent::init();
        $this->publishOptions['beforeCopy'] = function ($from, $to) {
            $dirname = basename(dirname($from));
            return $dirname === 'fonts' || $dirname === 'css';
        };
    }
}
```

El ejemplo anterior define un asset bundle para el ["fontawesome" package](http://fontawesome.io/). Especificando
la opción de publicación `beforeCopy`, solo los subdirectorios `fonts` y `css` serán publicados.

### Bower y NPM Assets <a name="bower-npm-assets"></a>
larnu committed
209

210
La mayoría de paquetes JavaScript/CSS se gestionan con [Bower](http://bower.io/) y/o [NPM](https://www.npmjs.org/).
larnu committed
211 212 213
Si tu aplicación o extensión usa estos paquetes, se recomienda seguir los siguientes pasos para gestionar los assets en
 la librería:

214 215
1. Modificar el archivo `composer.json` de tu aplicación o extensión e introducir el paquete en la lista `require`.
   Se debe usar `bower-asset/PackageName` (para paquetes Bower) o `npm-asset/PackageName` (para paquetes NPM) para
larnu committed
216
   referenciar la librería.
217 218
2. Crear una clase asset bundle y listar los archivos JavaScript/CSS que se planea usar en la aplicación o extensión.
   Se debe especificar la propiedad [[yii\web\AssetBundle::sourcePath|sourcePath]] como `@bower\PackageName` o
larnu committed
219 220 221
   `@npm\PackageName`. Esto se debe a que Composer instalará el paquete Bower o NPM en el correspondiente directorio de
    este alias.

222 223
> Nota: Algunos paquetes pueden distribuir sus archivos en subdirectorios. Si es el caso, se debe especificar el
  subdirectorio como valor del [[yii\web\AssetBundle::sourcePath|sourcePath]]. Por ejemplo, [[yii\web\JqueryAsset]]
larnu committed
224 225 226 227
  usa `@bower/jquery/dist` en vez de `@bower/jquery`.

## Uso de Asset Bundles <a name="using-asset-bundles"></a>

228 229
Para usar un asset bundle, debe registrarse con una [vista](structure-views.md) llamando al método
[[yii\web\AssetBundle::register()]]. Por ejemplo, en plantilla de vista se puede registrar un asset bundle como en el
larnu committed
230 231 232 233 234 235 236
siguiente ejemplo:

```php
use app\assets\AppAsset;
AppAsset::register($this);  // $this representa el objeto vista
```

237 238
> Información: El método [[yii\web\AssetBundle::register()]] devuelve un objeto asset bundle que contiene la
  información acerca de los assets publicados, tales como [[yii\web\AssetBundle::basePath|basePath]] o
larnu committed
239 240
  [[yii\web\AssetBundle::baseUrl|baseUrl]].

241 242
Si se registra un asset bundle en otro lugar, se debe proporcionar la vista necesaria al objeto. Por ejemplo, para
registrar un asset bundle en una clase [widget](structure-widgets.md), se puede obtener el objeto vista mediante
larnu committed
243 244
`$this->view`.

245 246
Cuando se registra un asset bundle con una vista, por detrás, Yii registrará todos sus asset bundles dependientes.
Y si un asset bundle se encuentra en un directorio inaccesible por la Web, éste será publicado a un directorio Web
247
público. Después cuando la vista renderice una página, se generarán las etiquetas (tags) `<link>` y `<script>`  para
248 249
los archivos CSS y JavaScript listados en los bundles registrados. El orden de estas etiquetas será determinado por
las dependencias entre los bundles registrados y los otros assets listados en las propiedades
larnu committed
250 251 252 253
[[yii\web\AssetBundle::css]] y [[yii\web\AssetBundle::js]].

### Personalización de Asset Bundles <a name="customizing-asset-bundles"></a>

254
Yii gestiona los asset bundles a través de un componente de aplicación llamado `assetManager` que está implementado
255
por [[yii\web\AssetManager]]. Configurando la propiedad [[yii\web\AssetManager::bundles]], se puede personalizar el
larnu committed
256
comportamiento (behavior) de un asset bundle. Por ejemplo, de forma predeterminada, el asset bundle [[yii\web\Jquery]]
257 258
, utiliza el archivo `jquery.js` desde el paquete Bower instalado. Para mejorar la disponibilidad y el rendimiento se
puede querer usar la versión alojada por Google. Ésta puede ser obtenida configurando `assetManager` en la
larnu committed
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
configuración de la aplicación como en el siguiente ejemplo:

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

279
Del mismo modo, se pueden configurar múltiples asset bundles a través de [[yii\web\AssetManager::bundles]]. Las claves
larnu committed
280
del array deben ser los nombres de clase (sin la primera barra invertida) de los asset bundles, y los valores del array
larnu committed
281
 deben ser las correspondientes [configuraciones de arrays](concept-configurations.md).
larnu committed
282

283
> Consejo: Se puede elegir condicionalmente que assets se van a usar en un asset bundle. El siguiente ejemplo
larnu committed
284 285 286 287 288 289 290 291 292 293
muestra como usar `jquery.js` en el entorno de desarrollo y `jquery.min.js` en los otros casos:
>
> ```php
> 'yii\web\JqueryAsset' => [
>     'js' => [
>         YII_ENV_DEV ? 'jquery.js' : 'jquery.min.js'
>     ]
> ],
> ```

294 295
Se puede deshabilitar uno o más asset bundles asociando `false` a los nombres de los asset bundles que se quieran
deshabilitar. Cuando se registra un asset bundle deshabilitado con una vista, ninguno de sus bundles dependientes será
larnu committed
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
registrado, y la vista tampoco incluirá ningún asset del bundle en la página que se renderice.
Por ejemplo, para deshabilitar [[yii\web\JqueryAsset]], se puede usar la siguiente configuración:

```php
return [
    // ...
    'components' => [
        'assetManager' => [
            'bundles' => [
                'yii\web\JqueryAsset' => false,
            ],
        ],
    ],
];
```

Además se pueden deshabilitar *todos* los asset bundles asignando `false` a [[yii\web\AssetManager::bundles]].

### Mapeo de Assets (Asset Mapping) <a name="asset-mapping"></a>

316 317 318 319
A veces se puede querer "arreglar" rutas de archivos incorrectos/incompatibles usadas en múltiples asset bundles.
Por ejemplo, el bundle A usa `jquery.min.js` con versión 1.11.1, y el bundle B usa `jquery.js` con versión 2.11.1.
Mientras que se puede solucionar el problema personalizando cada bundle, una forma más fácil, es usar la
característica *asset map* para mapear los assets incorrectos a los deseados. Para hacerlo, se tiene que configurar la
larnu committed
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
propiedad [[yii\web\AssetManager::assetMap]] como en el siguiente ejemplo:

```php
return [
    // ...
    'components' => [
        'assetManager' => [
            'assetMap' => [
                'jquery.js' => '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
            ],
        ],
    ],
];
```

335 336
Las claves de [[yii\web\AssetManager::assetMap|assetmMap]] son los nombres de los assets que se quieren corregir,
y los valores son las rutas de los assets deseados. Cuando se registra un asset bundle con una vista, cada archivo de
larnu committed
337
asset relativo de [[yii\web\AssetBundle::css|css]] y [[yii\web\AssetBundle::js|js]] serán contrastados con este mapa.
338
Si se detecta que alguna de estas claves es la última parte de un archivo asset (prefijado con
larnu committed
339 340 341 342
[[yii\web\AssetBundle::sourcePath]], si esta disponible), el correspondiente valor reemplazará el asset y será
registrado con la vista.
Por ejemplo, un archivo asset `mi/ruta/a/jquery.js` concuerda con la clave `jquery.js`.

343
> Nota: Sólo los assets especificados usando rutas relativas están sujetos al mapeo de assets. Y las rutas de los
larnu committed
344 345 346 347
assets destino deben ser tanto URLs absolutas o rutas relativas a [[yii\web\AssetManager::basePath]].

### Publicación de Asset <a name="asset-publishing"></a>

348 349
Como se ha comentado anteriormente, si un asset bundle se encuentra en un directorio que no es accesible por la Web,
este asset será copiado a un directorio Web cuando se registre el bundle con una vista. Este proceso se llama
larnu committed
350 351
*publicación de assets*, y se efectúa automáticamente por el [[yii\web\AssetManager|asset manager]].

352
De forma predeterminada, los assets se publican en el directorio `@webroot/assets` cuando corresponden a la URL
353
`@web\assets`. Se puede personalizar esta ubicación configurando las propiedades
larnu committed
354 355
[[yii\web\AssetManager::basePath|basePath]] y [[yii\web\AssetManager::baseUrl|baseUrl]].

356
En lugar de publicar los assets copiando archivos, se puede considerar usar enlaces simbólicos, si tu
357
SO (sistema operativo) y servidor Web lo permiten. Esta característica se puede habilitar estableciendo el valor de
larnu committed
358 359 360 361 362 363 364 365 366 367 368 369 370
[[yii\web\AssetManager::linkAssets|linkAssets]] en `true`.

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

371
Con la anterior configuración, el gestor de assets creará un enlace simbólico a la ruta de origen del asset bundle
larnu committed
372 373 374 375
cuando éste sea publicado. Esto es más rápido que copiar archivos y también asegura que siempre estén actualizados.

## Los Asset Bundles más Comunes <a name="common-asset-bundles"></a>

376
El código del núcleo de Yii tiene definidos varios asset bundles. Entre ellos, los siguientes bundles son los más
larnu committed
377 378
usados y pueden referenciarse en códigos de aplicaciones o extensiones.

379 380
- [[yii\web\YiiAsset]]: Principalmente incluye el archivo `yii.js` que implementa un mecanismo de organización de
  código JavaScript en los módulos. También proporciona soporte especial para los atributos `data-method` y
larnu committed
381 382 383
  `data-confirm` y otras característica útiles.
- [[yii\web\JqueryAsset]]: Incluye el archivo `jquery.js` desde el paquete Bower jQuery.
- [[yii\bootstrap\BootstrapAsset]]: Incluye el archivo CSS desde el framework Twitter Bootstrap.
384
- [[yii\bootstrap\BootstrapPluginAsset]]: Incluye el archivo JavaScript desde el framework Twitter Bootstrap para dar
larnu committed
385 386 387
  soporte a los plugins JavaScript de Bootstrap.
- [[yii\jui\JuiAsset]]: Incluye los archivos CSS y JavaScript desde la librería jQuery UI.

388 389
Si el código depende de jQuery, jQuery UI o Bootstrap, se pueden usar estos asset bundles predefinidos en lugar de
crear versiones propias. Si la configuración predeterminada de estos bundles no satisface las necesidades, se puede
larnu committed
390 391 392 393
personalizar como se describe en la subsección [Personalización de Asset Bundles](#customizing-asset-bundles).

## Conversión de Assets <a name="asset-conversion"></a>

394 395 396
En lugar de escribir código CSS y/o JavaScript directamente, los desarrolladores a menudo escriben código usando una
sintaxis extendida y usan herramientas especiales para convertirlos en CSS/JavaScript. Por ejemplo, para código CSS se
puede usar [LESS](http://lesscss.org) o [SCSS](http://sass-lang.com/); y para JavaScript se puede usar
larnu committed
397 398
[TypeScript](http://www.typescriptlang.org/).

399
Se pueden listar los archivos asset con sintaxis extendida (extended syntax) en [[yii\web\AssetBundle::css|css]] y
larnu committed
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
[[yii\web\AssetBundle::js|js]] en un asset bundle. Por ejemplo:

```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',
    ];
}
```

420 421 422
Cuando se registra uno de estos asset bundles en una vista, el [[yii\web\AssetManager|asset manager]] ejecutará
automáticamente las herramientas pre-procesadoras para convertir los assets de sintaxis extendidas reconocidas en
CSS/JavaScript. Cuando la vista renderice finalmente una página, se incluirán los archivos CSS/JavaScript
larnu committed
423 424
en la página, en lugar de los assets originales en sintaxis extendidas.

425
Yii usa las extensiones de archivo para identificar que sintaxis extendida se está usando. De forma predeterminada se
larnu committed
426 427 428 429 430 431 432 433
reconocen las siguientes sintaxis y extensiones de archivo.

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

434
Yii se basa en las herramientas pre-procesadoras instalada para convertir los assets. Por ejemplo, para usar
larnu committed
435 436
[LESS](http://lesscss.org/) se debe instalar el comando pre-procesador `lessc`.

437
Se pueden personalizar los comandos de los pre-procesadores y las sintaxis extendidas soportadas configurando
larnu committed
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
[[yii\web\AssetManager::converter]] como en el siguiente ejemplo:

```php
return [
    'components' => [
        'assetManager' => [
            'converter' => [
                'class' => 'yii\web\AssetConverter',
                'commands' => [
                    'less' => ['css', 'lessc {from} {to} --no-color'],
                    'ts' => ['js', 'tsc --out {to} {from}'],
                ],
            ],
        ],
    ],
];
```

456 457 458 459
En el anterior ejemplo se especifican las sintaxis extendidas soportadas a través de la propiedad
[[yii\web\AssetConverter::commands]]. Las claves del array son los nombres de extensión de archivo (sin el punto), y
los valores del array las extensiones de archivo resultantes y los comandos para realizar la conversión de assets.
Los tokens `{from}` y `{to}` en los comandos se reemplazarán por las rutas de origen de los archivos asset y las rutas
larnu committed
460 461
de destino de los archivos asset.

462 463 464
> Información: Hay otras maneras de trabajar con las assets de sintaxis extendidas, además de la descrita
  anteriormente. Por ejemplo, se pueden usar herramientas generadoras tales como [grunt](http://gruntjs.com/) para
  monitorear y convertir automáticamente los assets de sintaxis extendidas. En este caso, se deben listar los archivos
larnu committed
465 466 467 468
  CSS/JavaScript resultantes en lugar de los archivos de originales.

## Combinación y Compresión de Assets <a name="combining-compressing-assets"></a>

469
Una página web puede incluir muchos archivos CSS y/o JavaScript. Para reducir el número de peticiones (requests)
470
HTTP y el tamaño total de descarga de estos archivos, una práctica común es combinar y comprimir uno o
larnu committed
471 472
varios archivos, y después incluir los archivos comprimidos en las páginas Web.

473 474
>Información: La combinación y compresión de assets es habitualmente necesario cuando una aplicación se encuentra en
modo de producción. En modo de desarrollo, es más conveniente usar los archivos CSS/JavaScript originales por temas
larnu committed
475 476
relacionados con el debugging.

477 478
En el siguiente ejemplo, se muestra una propuesta para combinar y comprimir archivos asset sin necesidad de modificar
el código de la aplicación.
larnu committed
479 480 481 482 483

1. Buscar todos los asset bundles en la aplicación que se quieran combinar y comprimir.
2. Dividir estos bundles en uno o más grupos. Tenga en cuenta que cada bundle solo puede pertenecer a un único grupo.
3. Combina/Comprime los archivos CSS de cada grupo en un único archivo. Hace lo mismo para los archivos JavaScript.
4. Define un nuevo asset bundle para cada grupo:
484
    * Establece las propiedades [[yii\web\AssetBundle::css|css]] y [[yii\web\AssetBundle::js|js]] para que sean los
larnu committed
485
      archivos CSS y JavaScript combinados, respectivamente.
486
    * Personaliza los asset bundles en cada grupo configurando sus propiedades [[yii\web\AssetBundle::css|css]] y
larnu committed
487 488
      [[yii\web\AssetBundle::js|js]] para que sean el nuevo asset bundle creado para el grupo.

489 490
Usando este propuesta, cuando se registre un asset bundle en una vista, se genera un registro automático del nuevo
asset bundle para el grupo al que pertenece el bundle original. Y como resultado, los archivos combinados/comprimidos
larnu committed
491 492 493 494 495 496
se incluyen en la página, en lugar de los originales.

### Un Example <a name="example"></a>

Vamos a usar un ejemplo para explicar la propuesta anterior.

497
Asumiendo que la aplicación tenga dos páginas X e Y. La página X utiliza el asset bundle A, B y C mientras que la
larnu committed
498 499
página Y usa los asset bundles B, C y D.

500
Hay dos maneras de dividir estos asset bundles. Uno es usar un único grupo que incluye todos los asset bundles,
501
el otro es poner (A, B y C) en el Grupo X, y (B, C, D) en el grupo Y. ¿Cuál es mejor? El primero tiene la ventaja
502 503
de que las dos páginas comparten los mismos archivos CSS y JavaScript combinados, que producen una caché HTTP más
efectiva. Por otra parte, por el hecho de que un único grupo contenga todos los bundles, los archivos JavaScript serán
504 505
más grandes y por tanto incrementan el tiempo de transmisión del archivo inicial. En este ejemplo, se usará la primera
opción, ej., usar un único grupo que contenga todos los bundles.
larnu committed
506

507
> Información: Dividiendo los asset bundles en grupos no es una tarea trivial. Normalmente requiere un análisis de los
508
  datos del tráfico real de varios assets en diferentes páginas. Al principio, se puede empezar con un
larnu committed
509 510
  único grupo para simplificar.

511 512
Se pueden usar herramientas existentes (ej. [Closure Compiler](https://developers.google.com/closure/compiler/),
[YUI Compressor](https://github.com/yui/yuicompressor/)) para combinar y comprimir todos los bundles. Hay que tener en
larnu committed
513
cuenta que los archivos deben ser combinados en el orden que satisfaga las dependencias entre los bundles.
514
Por ejemplo, si el Bundle A depende del B que depende a su vez de C y D, entonces, se deben listar los archivos asset
larnu committed
515 516
empezando por C y D, seguidos por B y finalmente A.

517 518
Después de combinar y comprimir obtendremos un archivo CSS y un archivo JavaScript. Supongamos que se llaman
`all-xyz.css` y `all-xyz.js`, donde `xyz` representa un timestamp o un hash que se usa para generar un nombre de
larnu committed
519 520
archivo único para evitar problemas con la caché HTTP.

521
Ahora estamos en el último paso. Configurar el [[yii\web\AssetManager|asset manager]] como en el siguiente ejemplo en
larnu committed
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
la configuración de la aplicación:

```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']],
            ],
        ],
    ],
];
```

546 547 548 549
Como se ha explicado en la subsección [Personalización de Asset Bundles](#customizing-asset-bundles), la anterior
configuración modifica el comportamiento predeterminado de cada bundle. En particular, el Bundle A, B, C y D ya no
tendrán ningún archivo asset. Ahora todos dependen del bundle `all` que contiene los archivos combinados `all-xyz.css`
y `all-xyz.js`. Por consiguiente, para la Página X, en lugar de incluir los archivos originales desde los bundles A, B
larnu committed
550 551
y C, solo se incluirán los dos archivos combinados; pasa lo mismo con la Página Y.

552 553
Hay un último truco para hacer que el enfoque anterior se adapte mejor. En lugar de modificar directamente el archivo
de configuración de la aplicación, se puede poner el array del personalización del bundle en un archivo separado y que
larnu committed
554 555 556 557 558 559
se incluya condicionalmente este archivo en la configuración de la aplicación. Por ejemplo:

```php
return [
    'components' => [
        'assetManager' => [
560
            'bundles' => require(__DIR__ . '/' . (YII_ENV_PROD ? 'assets-prod.php' : 'assets-dev.php')),
larnu committed
561 562 563 564 565
        ],
    ],
];
```

566
Es decir, el array de configuración del asset bundle se guarda en `asset-prod.php` para el modo de producción, y
larnu committed
567 568 569 570 571 572
`assets-del.php` para los otros modos.

### Uso del Comando `asset` <a name="using-asset-command"></a>

Yii proporciona un comando de consola llamado `asset` para automatizar el enfoque descrito.

573 574
Para usar este comando, primero se debe crear un archivo de configuración para describir que asset bundle se deben
combinar y cómo se deben agrupar. Se puede usar el sub-comando `asset/template` para generar una plantilla primero y
larnu committed
575 576 577 578 579 580
después modificarla para que se adapte a nuestras necesidades.

```
yii asset/template assets.php
```

581
El comando genera un archivo llamado `assets.php` en el directorio actual. El contenido de este archivo es similar al
larnu committed
582 583 584 585 586 587 588 589 590 591
siguiente código:

```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 [
592
    // Ajustar comando/callback para comprimir los ficheros JavaScript:
larnu committed
593
    'jsCompressor' => 'java -jar compiler.jar --js {from} --js_output_file {to}',
594
    // Ajustar comando/callback para comprimir los ficheros CSS:
larnu committed
595
    'cssCompressor' => 'java -jar yuicompressor.jar --type css {from} -o {to}',
596
    // La lista de assets bundles para comprimir:
larnu committed
597 598 599 600
    'bundles' => [
        // 'yii\web\YiiAsset',
        // 'yii\web\JqueryAsset',
    ],
601
    // Asset bundle para la salida de compresión:
larnu committed
602 603 604 605 606 607 608 609 610
    'targets' => [
        'all' => [
            'class' => 'yii\web\AssetBundle',
            'basePath' => '@webroot/assets',
            'baseUrl' => '@web/assets',
            'js' => 'js/all-{hash}.js',
            'css' => 'css/all-{hash}.css',
        ],
    ],
611
    // Configuración del Asset manager:
larnu committed
612 613 614 615 616
    'assetManager' => [
    ],
];
```

617 618
Se debe modificar este archivo para especificar que bundles plantea combinar en la opción `bundles`. En la opción
`targets` se debe especificar como se deben dividir entre los grupos. Se puede especificar uno o más grupos,
larnu committed
619 620
como se ha comentado.

621
> Nota: Debido a que los alias `@webroot` y `@web` no están disponibles en la aplicación de consola, se deben definir
larnu committed
622 623
  explícitamente en la configuración.

624
Los archivos JavaScript se combinan, comprimen y guardan en `js/all-{hash}.js` donde {hash} se reemplaza con el hash
larnu committed
625 626
del archivo resultante.

627 628 629 630
Las opciones `jsCompressor` y `cssCompressor` especifican los comandos de consola o llamadas PHP (PHP callbacks) para
realizar la combinación/compresión de JavaScript y CSS. De forma predeterminada Yii usa
[Closure Compiler](https://developers.google.com/closure/compiler/) para combinar los archivos JavaScript y
[YUI Compressor](https://github.com/yui/yuicompressor/) para combinar archivos CSS. Se deben instalar las herramientas
larnu committed
631 632
manualmente o ajustar sus configuraciones para usar nuestras favoritas.

633
Con el archivo de configuración, se puede ejecutar el comando `asset` para combinar y comprimir los archivos asset y
larnu committed
634 635 636 637 638 639
después generar un nuevo archivo de configuración de asset bundles `asset-prod.php`:

```
yii asset assets.php config/assets-prod.php
```

640
El archivo de configuración generado se puede incluir en la configuración de la aplicación, como se ha descrito en la
larnu committed
641 642
anterior subsección.

643 644
> Información: Usar el comando `asset` no es la única opción de automatizar el proceso de combinación y compresión.
  Se puede usar la excelente herramienta de ejecución de tareas [grunt](http://gruntjs.com/) para lograr el mismo
larnu committed
645
  objetivo.