CSS/JS/Asset Compression in CakePHP
Thursday, April 9th 2009, 12:23am
Topics: Tutorials, CakePHP
Tags: CSS, Javascript, Compression, Assets
Comments: 25
Permalink -
Tinylink
The other day I spent way too many hours trying to figure out CakePHPs built in CSS and JS compression system. To say the least, its not really built in, you have to configure and do a lot of it yourself. I did much searching and found tutorials that didn't work, or using custom built helpers that were of no use, and in the end I wrote my own script (based off webroot/css.php written by gwoo). My script does the following:
To use my asset compression script, create a file called assets.php within webroot, and then copy and paste the code found at the end of this post. Once you have done this, download and place the jsmin.php file within /vendors/ or /app/vendors/ (the JSMin file should be named jsmin.php to work). The next step is to create a folder called assets within your /app/tmp/cache/ directory, and chmod the permissions to 777. The final step is to uncomment the filtering in core.php and set the path to assets.php.
Now to take it for a test spin! Once you have uncommented the configuration, direct your browser to the actual JS and CSS paths to see if it works (http://www.domain.com/ccss/style.css), and that's it! Hope this has been helpful and easy, like it should have been!
- Compresses both CSS and JS, using one file
- Caches the assets, and recaches if a change is made to the original
- Comes prebuilt with CSS compression
- Must download and install JSMin
- Extremely easy to install and configure
To use my asset compression script, create a file called assets.php within webroot, and then copy and paste the code found at the end of this post. Once you have done this, download and place the jsmin.php file within /vendors/ or /app/vendors/ (the JSMin file should be named jsmin.php to work). The next step is to create a folder called assets within your /app/tmp/cache/ directory, and chmod the permissions to 777. The final step is to uncomment the filtering in core.php and set the path to assets.php.
Configure::write('Asset.filter.css', 'assets.php');
Configure::write('Asset.filter.js', 'assets.php');Now to take it for a test spin! Once you have uncommented the configuration, direct your browser to the actual JS and CSS paths to see if it works (http://www.domain.com/ccss/style.css), and that's it! Hope this has been helpful and easy, like it should have been!
<?php
/**
* Compress and caches asset files: js, css (can be altered for other assets)
*
* Written by Miles Johnson (http://www.milesj.me), snippets from original CakePHP team
*
* CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
* Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @filesource
* @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
// No cake installation
if (!defined('CAKE_CORE_INCLUDE_PATH')) {
header('HTTP/1.1 404 Not Found');
exit('File Not Found');
}
// Get asset type
$ext = trim(strrchr($url, '.'), '.');
$assetType = ($ext === 'css') ? 'css' : 'js';
// Wrong file
if (preg_match('|\.\.|', $url) || !preg_match('|^c'. $assetType .'/(.+)$|i', $url, $regs)) {
die('Wrong File Name');
}
$cachePath = CACHE .'assets'. DS . str_replace(array('/','\\'), '-', $regs[1]);
$fileName = $assetType .'/'. $regs[1];
if ($assetType == 'css') {
$filePath = CSS . $regs[1];
$fileType = 'text/css';
} else {
$filePath = JS . $regs[1];
$fileType = 'text/javascript';
}
if (!file_exists($filePath)) {
die('Asset Not Found');
}
/**
* Compress the asset
* @param string $path
* @param string $name
* @return string
*/
function compress($path, $name, $type) {
$input = file_get_contents($path);
if ($type == 'css') {
$stylesheet = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $input);
$stylesheet = str_replace(array("\r\n", "\r", "\n", "\t", '/\s\s+/', ' ', ' '), '', $stylesheet);
$stylesheet = str_replace(array(' {', '{ '), '{', $stylesheet);
$stylesheet = str_replace(array(' }', '} '), '}', $stylesheet);
$output = $stylesheet;
} else {
App::import('Vendor', 'jsmin');
$output = JSMin::minify($input);
}
$ratio = 100 - (round(strlen($output) / strlen($input), 3) * 100);
$output = "/* File: $name, Ratio: $ratio% */\n". $output;
return $output;
}
/**
* Cache the asset
* @param string $path
* @param string $content
* @return string
*/
function cacheAsset($path, $content) {
if (!is_dir(dirname($path))) {
mkdir(dirname($path));
chmod($path, 0777);
}
if (!class_exists('File')) {
uses('file');
}
$cached = new File($path);
return $cached->write($content);
}
// Do compression and cacheing
if (file_exists($cachePath)) {
$templateModified = filemtime($filePath);
$cachedModified = filemtime($cachePath);
if ($templateModified > $cachedModified) {
$output = compress($filePath, $fileName, $assetType);
cacheAsset($cachePath, $output);
} else {
$output = file_get_contents($cachePath);
}
} else {
$output = compress($filePath, $fileName, $assetType);
cacheAsset($cachePath, $output);
$templateModified = time();
}
header("Date: ". date("D, j M Y G:i:s", $templateModified) ." GMT");
header("Content-Type: ". $fileType);
header("Expires: ". gmdate("D, j M Y H:i:s", time() + DAY) ." GMT");
header("Cache-Control: max-age=86400, must-revalidate"); // HTTP/1.1
header("Pragma: cache_asset"); // HTTP/1.0
print $output; ?>
25 Comments
aquitanda.com
Apr 9th 2009, 05:46
twitter.com/bkno
Apr 24th 2009, 12:27
walkerhamilton.com
May 5th 2009, 14:31
May 8th 2009, 13:07
milesj.me
May 8th 2009, 14:05
bjornpost.com
May 11th 2009, 11:43
Please let me know, you have my e-mailaddress :).
theskatepa...ectory.com
May 11th 2009, 18:43
May 16th 2009, 12:20
But it breaks tinymce :(
May 16th 2009, 13:18
But it breaks tinymce :(
May 18th 2009, 12:31
Thanks!
geoffoliver.org
May 19th 2009, 15:52
google.com
Jun 4th 2009, 13:55
freakclimbing.com
Jun 11th 2009, 01:48
thanks for the nice script!
I just noticed that relative paths to images (background, etc) get broken! This is also the problem with tinymce.
Cheers again!
Dan
Jul 28th 2009, 10:59
To made TinyMCE work one solution is put the subdirectories of tinymce on /cjs like is on /js.
example: /app/weebroot/js/tinymce/tinymce_subfolders.
just copy to /app/weebroot/cjs/tinymce/tinymce_subfolders.
Works for me.
Same works with Shadowbox.
Oct 15th 2009, 15:11