Minify helper for cakephp
A minify helper for js and css assets.
Lately, I have been working on a pretty large scale website involving cakephp. With all the feature requests in place, it was time for optimization. I usually follow Yahoo's Developer Network's best practices - http://developer.yahoo.com/performance/rules.html. It has got fantastic set of rules in there ( a must read for every web developer).
It is the same set of rules I implemented for my website - Property Jungle - http://www.propertyjungle.in.
As I didn't want re-invent any wheels, I zeroed down to project minify found here - http://code.google.com/p/minify/. It provides the following best practices out-of-box.
1. Minimise HTTP request - Since it unifies javascript (js) and css assets, only one call for each should be issued by a page
2. Adds an Expires or a Cache-control header: You don't want your server to issue the same js and css assets for every page load for a given user session.
3. Gzip components : Does that!
4. Minify js and css: Does that too!
5. Configure Etags: Phew, does that too!
Pretty good number of performance improvements. Ok enough of the introduction. Lets dive in.
Here are the sets to follow to get things working.
1. Dump the min folder from the minify source in your webroot directory - It should be accessible by http://server-name/min
2. Dump my minify helper into the helpers folder --> /views/helpers.
3. Add an entry 'Minify' in the $helpers array of the controller which will serve your page request.
4. Use $minify->js() and $minify->css() functions in the layout. Both functions require an array of asset names without their extensions.
5. Add an entry Configure::write('MinifyAsset',true) in your core.php file. Setting it false during debugging or development phase would be a good idea.
The helper code is pretty self-explanatory. It basically generates the list and script tags for css and js respectively with the 'src' attribute pointing to the 'min' folder in pre-specified format (when the 'MinifyAsset' is set to true in the core). Setting it false, fetches the assets from js and css folders.
Hope this helps you in getting up to speed quick and make a pretty noticeable performance improvement to your website. Any feedback or constructive criticism would be appreciated.
-Ketan.
http://www.innovatechnologies.in ketan _d0t_ shah _At_ innovatechnologies.in
It is the same set of rules I implemented for my website - Property Jungle - http://www.propertyjungle.in.
As I didn't want re-invent any wheels, I zeroed down to project minify found here - http://code.google.com/p/minify/. It provides the following best practices out-of-box.
1. Minimise HTTP request - Since it unifies javascript (js) and css assets, only one call for each should be issued by a page
2. Adds an Expires or a Cache-control header: You don't want your server to issue the same js and css assets for every page load for a given user session.
3. Gzip components : Does that!
4. Minify js and css: Does that too!
5. Configure Etags: Phew, does that too!
Pretty good number of performance improvements. Ok enough of the introduction. Lets dive in.
Here are the sets to follow to get things working.
1. Dump the min folder from the minify source in your webroot directory - It should be accessible by http://server-name/min
2. Dump my minify helper into the helpers folder --> /views/helpers.
Helper Class:
<?php
/***
* Cakephp view helper to interface with http://code.google.com/p/minify/ project.
* Minify: Combines, minifies, and caches JavaScript and CSS files on demand to speed up page loads.
* @author: Ketan Shah - ketan.shah@gmail.com - http://www.innovatechnologies.in
* Requirements: An entry in core.php - "MinifyAsset" - value of which is either set 'true' or 'false'. False would be usually set during development and/or debugging. True should be set in production mode.
*/
Class MinifyHelper extends AppHelper{
var $helpers = array('Javascript','Html'); //used for seamless degradation when MinifyAsset is set to false;
function js($assets){
if(Configure::read('MinifyAsset')){
e(sprintf("<script type='text/javascript' src='%s'></script>",$this->_path($assets, 'js')));
}
else{
e($this->Javascript->link($assets));
}
}
function css($assets){
if(Configure::read('MinifyAsset')){
e(sprintf("<link type='text/css' rel='stylesheet' href='%s' />",$this->_path($assets, 'css')));
}
else{
e($this->Html->css($assets));
}
}
function _path($assets, $ext){
$path = $this->webroot . "min/b=$ext&f=";
foreach($assets as $asset){
$path .= ($asset . ".$ext,");
}
return substr($path, 0, count($path)-2);
}
}
?>
3. Add an entry 'Minify' in the $helpers array of the controller which will serve your page request.
4. Use $minify->js() and $minify->css() functions in the layout. Both functions require an array of asset names without their extensions.
5. Add an entry Configure::write('MinifyAsset',true) in your core.php file. Setting it false during debugging or development phase would be a good idea.
The helper code is pretty self-explanatory. It basically generates the list and script tags for css and js respectively with the 'src' attribute pointing to the 'min' folder in pre-specified format (when the 'MinifyAsset' is set to true in the core). Setting it false, fetches the assets from js and css folders.
Hope this helps you in getting up to speed quick and make a pretty noticeable performance improvement to your website. Any feedback or constructive criticism would be appreciated.
-Ketan.
http://www.innovatechnologies.in ketan _d0t_ shah _At_ innovatechnologies.in








}else{
return $this->Html->script($url, $options);
}
}
public function css($path, $rel = null, $options = array()){
if(Configure::read('MinifyAsset') === true){
return $this->Html->css($this->_path($path, 'css'), $rel, $options);
}else{
return $this->Html->css($path, $rel, $options);
}
}
public function _path($assets, $ext){
if(!is_array($assets)){
$assets = array($assets);
}
$path = '/min-' . $ext . '?f=';
foreach($assets as $asset){
$path .= ($ext . '/' . $asset . '.' . $ext . ',');
}
return substr($path, 0, count($path) - 2);
}
}
?>
http://7shifts.com/blog/using-php-minify-in-cakephp/
any suggestions?
Greetz
VIEW: css('fancybox', null, array(), false); ?> link(array('jquery.easing.1.3' , 'jquery-ui-full-1.5.2.min'), false); ?>
How can I use your idea with my setup?
In the minify helper:
function css($assets, $media='screen'){
if(Configure::read('MinifyAsset')){
e(sprintf("<link type='text/css' rel='stylesheet' href='%s' media='$media'/>",$this->_path($assets, 'css')));
}
else{
e($this->Html->css($assets));
}
}
And in the view, I added a new array for print stylesheets, passing in the 'print' param.
$css_print_globals = array('common_print');
$minify->css($css_print_globals, 'print');
if i inspect with firebug and add the ../ back you the image appears. any ideas?
i tried looking through the code for a place that removes them but no such luck
apart from that it works cool
BTW.. i have also tried the fixes posted by Claudinei and Lucas but that made things worse...
I am facing a issue while deleteing a record from a table , the table doesn't have any 'id' feild present, can you please help me out so that instead of adding/editing my primary key I can del data using my default Pk which is 'fldAccessID'.
Many Thanks,
Rahul Sinhaa
This is *not* a forum. Try asking this on cake's mailing list/google group and someone will answer. This is a place to leave comments related to the article.
I am very new to CakePHP and try to resolve the following error:
Warning (2): Invalid argument supplied for foreach() [APP/views/helpers/minify.php, line 34]
In my layout I replaced $html->css() with $minify->css()
But then I get the error.
You write:
4. Use $minify->js() and $minify->css() functions in the layout. Both functions require an array of asset names without their extensions.
How do I use the new function exactly? Do I need to add somehing more to my $minify->css()?
First, set the $min_documentRoot to $_SERVER['DOCUMENT_ROOT'].'app/webroot/' on min/config.php
$min_documentRoot = $_SERVER['DOCUMENT_ROOT'].'app/webroot/';After that, edit the helper and change that assets loop to match the following one:
foreach($assets as $asset){$path .= ("{$ext}/{$asset}.{$ext},");
}
there you go! at the view you just need to specify the file path after "app/webroot/js/" or "app/webroot/css/" without the file extension.
I also prefer to change "js" and "css" functions to make use of the cake helper to print out script/css tag. This helps javascript's and css's tags to be printed out inside <head> even if called on the view and not only on the layout.
function js($assets, $inline = false){
if(Configure::read('MinifyAsset')){
return $this->Javascript->link($this->_path($assets, 'js'), $inline);
}else{
return $this->Javascript->link($assets, $inline);
}
}
function css($assets, $rel = null, $htmlAttributes = array(), $inline = false) {
if(Configure::read('MinifyAsset')){
return $this->Html->css($this->_path($assets, 'css'), $rel, $htmlAttributes, $inline);
}else{
return $this->Html->css($assets, $rel, $htmlAttributes, $inline);
}
}
Got a lot of HTTP/1.0 400 Bad Request. It's seems to me that the minifier looks for a system file under the given path, it it only works if you give it a full file path such as /host/app/webroot/css, since it won't access http, therefore get .htaccess instructions.
And I also found the b=$ext; part of the url to be buggy.
So this is what I've done to your helper:
function _path($assets, $ext){
$path = $this->webroot . "min/f=";
foreach($assets as $asset){
$path .= $this->webroot."app/webroot/".$ext."/";
$path .= ($asset . ".$ext,");
}
return substr($path, 0, count($path)-2);
}
It works well. Ugly though to have the full path on the final source, but it works.
Thanks for your effort.
Thanks :-)
If you call your functions js +css in the constructor or beforeRender-callback of the helper you can even leave out to call them in your view/layout. The inclusion in the helper-array would be enough to have it included.
Optionally you could use the check of a constant to avoid double inclusion (if the helper is included more than once). Maybe the Html-/JavascriptHelper avoids that by default,don't know that for sure.
_k10_
Comments are closed for articles over a year old