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>&hellip; ");


                // 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

Download the source directly.

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.:

<!--METADATA NAME="Microsoft ActiveX Data Objects 2.5 Library" TYPE="TypeLib" UUID="{00000205-0000-0010-8000-00AA006D2EA4}"-->

Advertisement

Feedback

Voting Panel
Is this useful?
or
Did you find any bugs?
or
Could the script be significantly improved?
or
Rate this script: (0=poor, 5=very good)
Answers are anonymous, only the combined totals are stored. Uses cookies.