Home » Apache, Bash, Javascript, Linux Administration, Web Development

How to compress css & javascript: An alternative to mod_deflate or mod_gzip

1 June 2009 15 Comments

So, you have used Website Optimization Analyzer or you installed Yslow for Firefox or you discovered somewhere else that compressing your files (html, javascript & css) is a good thing to do. Unfortunately, it’s not always as easy as it looks to do this.

In Apache web hosting environments, there is a module called mod_deflate (for 2.x versions) or mod_gzip (for 1.3) versions. This is generally the easiest way to get content compressed. As in my last post about Magento, you should normally be able to enable this safely with the following lines inside your .htaccess file in your www root of your website:

<ifmodule mod_deflate.c>
# Insert filter
SetOutputFilter DEFLATE
# Netscape 4.x has some problems...
BrowserMatch ^Mozilla/4 gzip-only-text/html
# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4\.0[678] no-gzip
# MSIE masquerades as Netscape, but it is fine
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# Don't compress images
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
</ifmodule>

Then visit your website and in your browser right-click on the web page and choose “View Source”. In the source code, try and find a line that contains your stylesheet, then we go to whatsmyip compression checker and we enter the whole URL to your stylesheet there. To test, enter my css url.

http://www.opensourcetutor.com/wp-content/themes/hemingwayEx/style.css

You should see a big green tick and the site will say the CSS is compressed. Now, if you don’t, you either haven’t applied my above .htaccess settings yet or mod_deflate is not enabled on your server for you to access.

Alternative #1 – requires Apache mod_rewrite

This method is probably the best method I have seen to overcome the mod_deflate issue and we are only concerned about javascript and css files for now. PHP has an easy method to compress php files on the fly. What we need to do is gzip all our javascript & css files.

If you have shell access, you can run this command to take of the job for you. It will find each and every javascript file and css file and create a gzip copy.

find . -regex ".*\(css\|js\)$" -exec bash -c 'echo Compressing "{}" &amp;&amp; gzip -c --best "{}" > "{}.gz"' \;

The line above searches the current directory and any subdirectories for files with extensions .js or .css, then prints out that it is being compressed, then compresses with the highest compression in that directory leaving the original file as is.

Now, we need to tell our browser to access the gzip version *IF* it supports gzip encoding. To do this, we use the following in our .htaccess file. Make sure you have removed the above code if it wasn’t successful.

<files *.js.gz>
  AddType "text/javascript" .gz
  AddEncoding gzip .gz
</files>
<files *.css.gz>
  AddType "text/css" .gz
  AddEncoding gzip .gz
</files>
RewriteEngine on
#Check to see if browser can accept gzip files.
ReWriteCond %{HTTP:accept-encoding} gzip
RewriteCond %{HTTP_USER_AGENT} !Safari
#make sure there's no trailing .gz on the url
ReWriteCond %{REQUEST_FILENAME} !^.+\.gz$
#check to see if a .gz version of the file exists.
RewriteCond %{REQUEST_FILENAME}.gz -f
#All conditions met so add .gz to URL filename (invisibly)
RewriteRule ^(.+) $1.gz [QSA,L] 

The advantage of this Alternative is that our server doesn’t have to gzip / compress the javascript and css each time it is called. This eases the load up on the server as we already do the compression one time and then just call the compressed version from then after. The other advantage is that we don’t need to load up mod_deflate each time. This could be advantages if you are running a VPS with very low memory available.

If you have a static website, you could apply the same technique for all your html files. To do so, you would instead use this line:

find . -regex ".*\(html\|css\|js\)$" -exec bash -c 'echo Compressing "{}" &amp;&amp; gzip -c --best "{}" > "{}.gz"' \;

and then add this into your .htaccess also

<files *.html.gz>
  AddType "text/html" .gz
  AddEncoding gzip .gz
</files>

Technorati Tags: , , , , , ,

15 Comments »

  • Timm said:

    Looks very useful, but why do you keep Safari out on alternative #1??

  • salubrium (author) said:

    When I first implemented this, Safari didn’t unpack .gz files automatically like other browsers. I am not sure if this is still true. I don’t have or run Safari now so, it’s not easy to test.

  • Timm said:

    I found comments on another blog confirming that several modern browsers don’t support .gz file decompression: Safari, Konqueror and Google Chrome 2.0. With the alternate solution, those users won’t get the benefits of compression.

    Another issue is automating this in your deployment cycle (also mentioned in the post above): I’m often tweaking css on my live sites; using this approach I won’t be seeing any changes until I manually gzip the changed file. Is there any way to automate this?

  • cannon said:

    hello, I am using a simple godaddy economic plan.

    and yes, I have no access to my apache server. and shell :(

    will this still work?

    hope you can guide me on how to implement these one.

    hope you reply SAP

    I am planning to gzip jquery.js and jdgallery.js coz they are 100kb in size

  • salubrium (author) said:

    Download copies of your jquery.js and jdgallery.js. Use a utility called 7zip (if you are on windows) to gzip these files and give them a gz extension. Then upload them to the same directory where your original js files live. Add the details to your .htaccess file and test using the http://www.whatsmyip.org/ compression tool or Yslow extension in Firefox.

  • danreb said:

    Very useful information, thanks – I tried the alternative method and works like a charm.

  • faraz said:

    i’m using this code so if the gzip version of the file dosen’t exist apache does it on the fly.
    ———————————–

    AddType “text/html” .gz
    AddEncoding gzip .gz

    AddType “text/javascript” .gz
    AddEncoding gzip .gz

    AddType “text/css” .gz
    AddEncoding gzip .gz

    RewriteEngine on
    ReWriteCond %{HTTP:accept-encoding} gzip
    RewriteCond %{HTTP_USER_AGENT} !Safari
    ReWriteCond %{REQUEST_FILENAME} !^.+\.gz$
    RewriteCond %{REQUEST_FILENAME}.gz -f
    RewriteRule ^(.+) $1.gz [QSA,L]

    AddOutputFilterByType DEFLATE text/html
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
    —————————–

    how can i exclude these:
    Netscape 4.06-4.08
    IE6
    chrome 2.0

    like safari?
    RewriteCond %{HTTP_USER_AGENT} !Safari

  • salubrium (author) said:

    I haven’t tested it but something like this should ignore the browsers in question.


    RewriteCond %{HTTP_USER_AGENT} !^.*MSIE\ 6.0
    RewriteCond %{HTTP_USER_AGENT} !^.*Chrome.*
    RewriteCond %{HTTP_USER_AGENT} !^.*Mozilla/4\.0[678].*

  • PCM said:

    I tried to use the above technique and it works perfectly well, but one major problem for my pages. I am using SSIs on each page. When I make .gz file and uplaod it, then the server does not load the SSI. Please suggest me how to include SSI in .gz files.

  • mklee said:

    Helllo Techies,

    How to conditionally disable the mod_deflate based on the query string (EX: has_gender=) and how to check whether it works or not ?

  • salubrium (author) said:

    Check out the mod_rewrite Cheat Sheet here

    You will probably use something like (I haven’t tested and my regex’s aren’t that good, so you have to check it out)

    RewriteCond %{REQUEST_URI}% !(^*.has_gender=.*)$

    How to check? Trial and error.. maybe put a 301 redirect to a simple html page if the condition isn’t met until you have finished testing.

  • Raj Karun said:

    Hi I read several blogs and articles and this one actually solved my problem.
    There were actually 40 .js files in my web directory and used 7zip and the htaccess code its working great. I had a doubt while going through the code. It is very clearly explained in the htaccess code that we first check if the browser accepts Gzip file and then we send the Gzip file, in that case why should we specifically exclude browsers. Sorry if this is a stupid/blunt question.

    Raj

  • salubrium (author) said:

    You can read the other comments about why we exclude certain browsers. We ignore them because the don’t unpack the gz extension in the normal / expected way like other browsers.

  • ada said:

    How can I exclude a file on Alternative method 1? My sitemap plugin creates sitemap.xml.gz and I need to exclude it!

Leave your response!

Add your comment below, or trackback from your own site. You can also subscribe to these comments via RSS.

Be nice. Keep it clean. Stay on topic. No spam.

You can use these tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

This is a Gravatar-enabled weblog. To get your own globally-recognized-avatar, please register at Gravatar.