CSS Compressor
Audience Level
Beginner and above
Introduction
This JScript function scans a given directory for CSS files, backs-up each into a storage subfolder and then removes unnecessary whitespace and comments from all of the CSS files found before saving the changes. The idea behind this is simply to decrease the size of CSS files downloaded by web browsers and other clients to speed-up the serving of web pages.
Source Code
Function: doCompressCSS()
Description: Removes white-space and comments from CSS files in a given directory. Backs-up original files to a new directory. Does not touch files that have already been compressed.
Returns: String (HTML progress display)
History:
20050129 2204GMT v1 Andrew Urquhart Created
*/
function doCompressCSS(strCssFolderPath, strCssBackupFolderPath, strAuthorName) {
try {
if (!strCssFolderPath) {
throw new Error(1, "Required parameter \"strCssFolderPath\" was not defined");
}
if (!strCssBackupFolderPath) {
throw new Error(2, "Required parameter \"strCssBackupFolderPath\" was not defined");
}
var objO = [];
var objFSO = new ActiveXObject("Scripting.FileSystemObject");
var objFolder = objFSO.GetFolder(strCssFolderPath); // Get Folder object
// CREATE BACK-UP DIRECTORY
if (!objFSO.FolderExists(strCssBackupFolderPath)) {
// NOTE: THIS ASSUMES THAT THE BACK-UP DIRECTORY SHOULD BE A SUB-FOLDER OF THE CURRENT DIRECTORY.
objFSO.CreateFolder(strCssBackupFolderPath);
}
// ENUMERATE OVER FILES
objO.push("<ol>");
for (var objItem = new Enumerator(objFolder.Files); !objItem.atEnd(); objItem.moveNext()) {
var objFile = objItem.item();
var strFileName = objFile.name;
var strFilePath = "/css/" + strFileName;
var objDateModified = new Date(objFile.DateLastModified);
// PICK CSS FILES ONLY
if ((/\.css$/i).test(strFileName)) {
objO.push("<li><strong>Processing:</strong> <code><a href=\"" + strFilePath + "\">" + strFileName + "</a></code>… ");
// CHECK THAT FILE HAS NOT BEEN COMPRESSED BEFORE (IF IT HAS WE WANT TO SKIP IT)
// A PREVIOUSLY COMPRESSED FILE IS IDENTIFIED BY THE COMMENT IN THE FIRST LINE
var objFileStream_Read_check = objFile.OpenAsTextStream(1, -2); // 1=ForReading; -2=Tristate Default
var strFileData_check = objFileStream_Read_check.ReadLine();
objFileStream_Read_check.Close();
// SKIP FILE IF PREVIOUSLY COMPRESSED
if ((/AutoCompressDate/).test(strFileData_check)) {
objO.push("skipped (previously compressed)</li>");
continue;
}
// COPY CSS FILE TO BACKUP, OVERWRITING ANY PREVIOUS VERSIONS
var strBackupFileName = strCssBackupFolderPath + "\\" + strFileName;
objFile.Copy(strBackupFileName, true);
// OPEN FILE
var objStream = new ActiveXObject("ADODB.Stream");
var strF = ""; // File contents as string
objStream.Open();
try {
objStream.CharSet = "UTF-8";
objStream.LoadFromFile(Server.MapPath(strFilePath));
strF = objStream.ReadText();
}
catch (err) {
throw err;
}
finally {
objStream.Close(); // Always close the stream regardless of what happens
}
// PERFORM COMPRESSION
strF = strF.replace(/\/\*[^\*]*\*\//g, ""); // Kill comments
strF = strF.replace(/\t/g, ""); // Kill tabs
strF = strF.replace(/:\s+/g, ":"); // Kill space after colons
strF = strF.replace(/ +/g, " "); // Multiple white space characters
strF = strF.replace(/^\s*$/gm, ""); // Kill whitespace lines
strF = strF.replace(/^\s/g, ""); // Kill null lines
strF = strF.replace(/\s*\r\n\s*\}/g, "}"); // Kill lines and spaces before closing brackets
strF = strF.replace(/([\{;])\r\n/g, "$1"); // Kill newlines within a selector block
strF = "/* Author: \"" + strAuthorName + "\", File: \"" + strFileName + "\", PreCompressFileDate: \"" + objDateModified.toUTCString() + "\", AutoCompressDate: \"" + (new Date()).toUTCString() + "\" */\r\n" + strF;
// SAVE FILE
objStream.Open();
try {
objStream.CharSet = "UTF-8";
objStream.WriteText(strF);
objStream.SaveToFile(Server.MapPath(strFilePath), adSaveCreateOverWrite);
}
catch (err) {
throw err;
}
finally {
objStream.Close(); // Always close the stream regardless of what happens
}
objO.push("<strong>done</strong></li>");
}
}
objO.push("</ol>");
return objO.join(""); // Return results processing information
}
catch (err) {
throw new Error(err.number, "Function doCompressCSS() failed with parameters strCssFolderPath=\"" + strCssFolderPath + "\", strCssBackupFolderPath=\"" + strCssBackupFolderPath + "\", strAuthorName=\"" + strAuthorName + "\". Message=\r\n" + err.description);
}
}
Download
Example Usage
The following snippet of JScript ASP might be included in a page to trigger the function and display the result. A typical generated file looks like /css/default.css and might reduce each file by around 10-20%.
var strCssFolderPath = Server.MapPath("/css/");
var strCssBackupFolderPath = Server.MapPath("/css/backup/");
var strAuthorName = "Andrew Urquhart";
try {
Response.Write(doCompressCSS(strCssFolderPath, strCssBackupFolderPath, strAuthorName))
}
catch (err) {
Response.Write("<div class=\"error\">Failed to compress CSS files: " + Server.HTMLEncode(err.description) + " (" + err.number + ")</div>");
}
%>
Notes
Enabling GZip compression content negotiation at the server-side will significantly improve download performance of CSS files too.
If you encounter syntax errors with the ADO constants (i.e. “adSaveCreateOverWrite”)
then you need to add the ADODB Metadata Type library declaration to the top of your
“global.asa”, e.g.: