A Javascript/CSS compressor based on Yii's package system.
- A Java runtime engine must be installed for the YUI compressor
- Javascript and CSS compression of Yii clientscript packages (using YUI compressor)
- Does not interfere with scripts and CSS registered outside of packages
- Automatic or manually triggered compression
- Locking mechanism to prevent multiple concurrent compressions
- Workaround for the thundering herd problem
- Command-line maintenance script
You probably wonder, why yet another compression extension for Yii? The key difference is, that none of the existing solutions uses Yii's integrated package system for clientscripts. With this extension you can organize all your CSS and Javascript in packages and even define dependencies among them. This may not be very useful for smaller sites (even though you still can use the compressor there, too). But it proved to be extremely helpful when you have to deal with many Javascript files and want to cluster them into a couple of minified package files.
Note: You can even include Yii's core scripts in a package. Unfortunately some Zii widgets like
CListView
andCGridView
still don't use the package system packages. But this will hopefully be fixed in Yii 1.1.15.
Packages are set up in your config file. Javascript and CSS packages must be separate. Here's an example:
<?php
return array(
// ...
'clientScript' => array(
'class' => 'ext.packagecompressor.PackageCompressor'
'coreScriptPosition' => 2, // == POS_END
'packages' => array(
'forum-js' => array(
'baseUrl' => 'js',
'depends' => array('jQuery', 'maskedinput'),
'js' => array(
'modules/main.js',
'modules/editor.js',
'modules/forum.post.js',
'modules/forum.notify.js',
),
),
'forum-css' => array(
// requires write permission for this directory
'baseUrl' => 'css',
'css' => array(
'main.css',
'forum.css',
),
),
),
),
// ...
);
With the packages defined above you can now for example register the forum packages in the forum section of your site:
Yii::app()->clientScript->registerPackage('forum-js');
Yii::app()->clientScript->registerPackage('forum-css');
Your users will receive single js and CSS files until you reset a package with
./yiic packages reset
Whenever a package is registered through registerPackage()
a single compressed
file is served to the user. If there is no compressed file yet, all files from the
package get combined and compressed, then this single file is published by the asset manager.
The extension uses the application state (which gets cached automatically) to store
information about a compressed package. So after the initial delay during compression
all subsequent requests will get the compressed file delivered lightning fast.
There's also a command line tool to create the compressed file for a package manually, e.g. at deployment time and to reset a package.
The compressed file name will contain a hash to make sure that no visitor ever gets and outdated version of a compressed package.
Extract the package in protected/extensions
into a directory called packagecompressor
(remove the -x.y.z
suffix). Then configure the component to replace Yii's
CClientScript component:
protected/config/main.php
<?php
return array(
// ...
'components' => array(
'clientScript' => array(
'class' => 'ext.packagecompressor.PackageCompressor'
),
// ...
),
// ...
);
If you want to user the command-line utility, you should make the bundled command available in your console configuration:
protected/config/console.php
<?php
return array(
// ...
'commandMap' => array(
'packages' => array(
'class' => 'ext.packagecompressor.PackagesCommand',
),
// ...
),
// ...
);
Besides the usual CClientScript
properties the packager adds these other
configuration options, which you can set in your main.php
config file:
enableCompression
: Wether compression should be enabled at all. Default istrue
. It's recommended to turn this off during development.enableCssImageFingerPrinting
: Whether to enable automatic fingerprinting on CSS images, e.g. to add?acd4gd3sz
based on the md5 hash of the image file.combineOnly
: Wether all files should only be combined but not compressed. Default isfalse
. This is very useful to debug packaging issues.blockDuringCompression
: Wether other requests should pause during compression. Default istrue
. This could sometimes be problematic on websites with heavy load, because the mass of paused processes could eat up all server ressources. As a workaround you can set this tofalse
. In this case during compression any concurrent requests will be served the unminified single files instead. If you also don't want that, you can still create the minified version from the command line before you deploy.javaBin
: The path to your java binary. The default isjava
which assumes that the JRE binary is available in your OS' search path (which it usually is on linux systems).
This component comes with a maintenace command for yiic. It can be used to compress packages, reset packages or output details about compressed packages from the command line.
Note: It's important that the package configuration from your web configuration is also available in your console config. That means, you need have the same
clientScript
configuration in yourconsole.php
. You may want to use a shared include file to do so. If you want to compress from the command-line you also need to configure an asset manager and an alias forwebroot
. You also need to fix a problem with therequest
component which returns '.' as baseUrl on console:<?php 'aliases' => array( 'webroot' => realpath(__DIR__.'/../..'), ), 'components' => 'assetManager'=>array( 'class' =>'CAssetManager', 'basePath' =>realpath(__DIR__.'/../../assets'), 'baseUrl' =>'/assets', ), 'request' => array( 'baseUrl' => '', ), //...
Note 2: You need write permissions from the command line to the
state.bin
file in yourprotected/runtime
directory, if you want to reset packages.
Compress a package:
./yiic packages compress --name=<packagename>
Show meta information about a compressed package:
./yiic packages info --name=<packagename>
Reset all compressed packages:
./yiic packages reset
Reset specific package:
./yiic packages reset --name=<packagename>
CSS files often contain relative URL references to some asset files (images).
So if the compressed CSS file is published to the assets directory, these
paths will be broken (except if we'd also publish the images, which we don't).
As a workaround you can publish a CSS package into the same folder where the
source files reside. Therefore you have to specify a baseUrl
in your package.
<?php
return array(
// ...
'forum-css' => array(
'baseUrl' => 'css',
'css' => array(
'main.css',
'forum.css',
),
),
// ...
)
Now you can register this CSS package with
Yii::app()->clientScript->registerPackage('forum-css');
Note: Here the web server process must have write permissions to the CSS folder.
CSS packages can contain a media
specification which will be used when the package
is registered.
<?php
return array(
// ...
'main-css' => array(
'baseUrl' => 'css',
'media' => 'screen',
'css' => array(
'main.css',
'forum.css',
),
),
'main-css' => array(
'baseUrl' => 'css',
'media' => 'print',
'css' => array(
'print.css',
),
),
// ...
)
If you want to use a CDN for jQuery you can configure it just as you would without the compressor. Everything will work when you register such a package:
<?php
return array(
// ...
'clientScript' => array(
'class' => 'ext.packagecompressor.PackageCompressor'
'coreScriptPosition' => 2, // == POS_END
'scriptMap' => array(
'jquery.js' => 'https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.js',
),
'packages' => array(
'forum' => array(
'depends' => array('jQuery', 'maskedinput'),
'js' => array(
// ...
),
),
),
),
// ...
),
- PackageCompressor is not compatible with an absolute
baseUrl
(eg. CDN Hosting) in Yii's assetManager
- Fix external URLs that don't have a protocol like
//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.js
- Add
media
support for CSS.
- Add composer support
- Initial version