Open Source Software Technical Articles

Want the Best of the Wazi Blogs Delivered Directly to your Inbox?

Subscribe to Wazi by Email

Your email:

Connect with Us!

Current Articles | RSS Feed RSS Feed

Compress your web pages for better performance

  
  
  

Users always want faster access to web resources. If your website is sluggish and serves pages slowly, would-be visitors won't wait, and will go elsewhere instead. Fortunately, you can employ several tools to compress your code and output and thus send fewer bytes over the Net, enhancing download times and creating a better user experience.

We'll look at tools that can:

  • Set your web server to compress (zip) all of its output.
  • Minify your JavaScript code, to yield a shorter but equivalent version.
  • Clean up your CSS rules and HTML code and remove unnecessary contents.

Some of the tools you must apply before deploying your site, and some require configuration changes to Apache or whatever web server you use. We won't be going into any tools that require changing your program logic (for example, using jQuery to dynamically load JavaScript on demand, for a shorter initial download) because that approach can inject interesting bugs into your pages.

Deflate your output

Whenever a client browser requests a page from a server, it can specify whether it will accept compressed data (meaning that the client can decompress whatever it receives) by means of the Accept-Encoding request header. The server, if it is able to produce the requested compression, will include the Content-Encoding header in the returned data, showing what method it applied to the data.

You can easily see how this works with the wget command and Wazi's own servers. If you ask for the page without encoding, you get 76,250 bytes (about 75K):

> wget -S -nv -O wazi.html www.openlogic.com/wazi
  HTTP/1.1 200 OK
  Cache-Control: private
  Content-Type: text/html; charset=utf-8
  Server: Microsoft-IIS/7.5
  X-AspNet-Version: 2.0.50727
  X-Powered-By: ASP.NET
  Date: Sun, 16 Feb 2014 00:45:24 GMT
  Transfer-Encoding:  chunked
  Connection: keep-alive
  Connection: Transfer-Encoding
2014-02-15 22:45:24 URL:http://www.openlogic.com/wazi [76250] -> "wazi.html" [1]

However, if you include the Accept-Encoding header, you get the same data, but gzipped, reduced more than 80% to 14,315 bytes, or less than 14K:

> wget -S -nv -O wazi.compressed --header "Accept-Encoding: gzip, deflate, compress" www.openlogic.com/wazi
  HTTP/1.1 200 OK
  Cache-Control: private
  Content-Type: text/html; charset=utf-8
  Server: Microsoft-IIS/7.5
  X-AspNet-Version: 2.0.50727
  X-Powered-By: ASP.NET
  Vary: Accept-Encoding
  Content-Encoding: gzip
  Content-Length: 14315
  Date: Sun, 16 Feb 2014 00:46:10 GMT
  Connection: keep-alive
2014-02-15 22:46:10 URL:http://www.openlogic.com/wazi [14315/14315] -> "wazi.compressed" [1]

All commonly used web browsers support this kind of compression, and routinely ask servers if they can provide compressed data, so enabling this feature for your site is an easy win. To do so with Apache you have to enable mod_deflate; include a LoadModule deflate_module /path/to/your/mod_deflate.so line in your httpd.conf file. The path for the module depends on your distribution, but you can easily determine it by checking out the other current LoadModule lines. If the module doesn't exist, use your favorite package manager to get it; mod_deflate is standard, and available in distribution repositories.

You also have to specify what kind of MIME type results should be compressed. Edit your .htaccess file to include a list like this:

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE application/javascript 
  AddOutputFilterByType DEFLATE application/rss+xml 
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/xml 
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE text/css 
  AddOutputFilterByType DEFLATE text/html 
  AddOutputFilterByType DEFLATE text/javascript
  AddOutputFilterByType DEFLATE text/plain 
  AddOutputFilterByType DEFLATE text/richtext
  AddOutputFilterByType DEFLATE text/x-component 
  AddOutputFilterByType DEFLATE text/xsd 
  AddOutputFilterByType DEFLATE text/xsl 
  AddOutputFilterByType DEFLATE text/xml 
  AddOutputFilterByType DEFLATE image/svg+xml 
  AddOutputFilterByType DEFLATE image/x-icon
</IfModule>

Not all files should be compressed; for example, compressing an already compressed ZIP file before sending it to the client would be a waste of time.

Restart your Apache server, and from that moment on, the web server will be able to honor all data compression requests. If you're using another web server, check the project's documentation; changes along the lines of what we did for Apache will be in order, but since all major servers support data compression, enabling it shouldn't be a hard task.

Minify your JavaScript

Even if you are deflating its output, the files that your web server has to send should be as small as possible. Many tools can minify your JavaScript code, producing an equivalent but smaller version. As a side benefit, the software can obfuscate files, meaning that they will be harder to understand by third parties, thus providing some degree of intellectual property protection, and it can optimize them.

YUI Compressor 2.4.8, developed by the Yahoo! User Interface group, is provided as a Java jar file that you run on Linux, Windows, or OS X. To test it, I used the latest jQuery version 2 uncompressed file, which runs nearly 240K for 10,000 lines of code. For the test I purposely got the bigger development version of jQuery; for actual use on your site you would use the 81K production version.

To learn about YUI Compressor's options, type java -jar yuicompressor-2.4.8.jar --help. For my test I ran java -jar yuicompressor-2.4.8.jar -o jquery.yui.js jquery-2.1.0.js, and it produced a 127K file, about 50% size of the original. Just to give you a taste of minified code, the start of the new file looks like this:

/*!
 * jQuery JavaScript Library v2.1.0
 * http://jquery.com/
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 *
 * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2014-01-23T21:10Z
 */
(function(b,a){if(typeof module==="object"&&typeof module.exports==="object"){module.exports=b.document?a(b,true):function(c){if(!c.document){throw new Error("jQuery requires a window with a document")}
return a(c)}}else{a(b)}}(typeof window!=="undefined"?window:this,function(window,noGlobal){var arr=[];var slice=arr.slice;var concat=arr.concat;var push=arr.push;var indexOf=arr.indexOf;var class2type={
};var toString=class2type.toString;var hasOwn=class2type.hasOwnProperty;var trim="".trim;var support={};var document=window.document,version="2.1.0",jQuery=function(selector,context){return new jQuery.f
n.init(selector,context)},rmsPrefix=/^-ms-/,rdashAlpha=/-([\da-z])/gi,fcamelCase=function(all,letter){return letter.toUpperCase()};jQuery.fn=jQuery.prototype={jquery:version,constructor:jQuery,selector:
"",length:0,toArray:function(){return slice.call(this)},get:function(num){return num!=null?(num<0?this[num+this.length]:this[num]):slice.call(this)},pushStack:function(elems){var ret=jQuery.merge(this.c
onstructor(),elems);ret.prevObject=this;ret.context=this.context;return ret},each:function(callback,args){return jQuery.each(this,callback,args)},map:function(callback){return this.pushStack(jQuery.map(
this,function(elem,i){return callback.call(elem,i,elem)}))},slice:function(){return this.pushStack(slice.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},e
q:function(i){var len=this.length,j=+i+(i<0?len:0);return this.pushStack(j>=0&&j<len?[this[j]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:push,sort:arr.sort,splice:arr.spli
ce};jQuery.extend=jQuery.fn.extend=function(){var options,name,src,copy,copyIsArray,clone,target=arguments[0]||{},i=1,length=arguments.length,deep=false;if(typeof target==="boolean"){deep=target;target=
arguments[i]||{};i++}if(typeof target!=="object"&&!jQuery.isFunction(target)){target={}}if(i===length){target=this;i--}for(;i<length;i++){if((options=arguments[i])!=null){for(name in options){src=target
[name];copy=options[name];if(target===copy){continue}if(deep&&copy&&(jQuery.isPlainObject(copy)||(copyIsArray=jQuery.isArray(copy)))){if(copyIsArray){copyIsArray=false;clone=src&&jQuery.isArray(src)?src [...]

Three online JavaScript minifying service alternatives
The javascript-minifier page lets you paste your code and get a minified alternative; for a command-line process you can also invoke it as a web service, through a POST request. Packer is another online alternative, which you can also use as a PHP, Perl, or .NET application. And jscompress is based upon both Packer and JSMin, an old tool by Douglas Crockford.

Note that comments starting with /*! are kept, so copyright and license texts won't be taken out. (Other compressors may not make that distinction, and may take out all comments, whatever their origin.) The produced code is more compact than the original, and if it were further compressed by Apache as we saw earlier, it would go down to about 30K, which is just an eighth of the original size.

We'll revisit YUI Compressor again when we consider how to compress CSS, but let's now look at another compressor that offers even more options and code trimming.

Google's Closure is in fact more than a minifier, because it not only removes extra white space, line end characters, and the like, it also revises your JavaScript code into better JavaScript by analyzing your code, removing useless bits, and rewriting whatever's left into a smaller, tighter, more efficient version. As an extra, it warns about possible JavaScript problems. You can use Closure as a web service or a RESTful API, but I went with a command-line Java jar version. The latest version is dated 1/10/2014, so it's quite up-to-date.

Closure has far too many options to list; after unzipping your download, run java -jar compiler.jar --help to check them out. Working again with the jQuery source code, I ran java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js jquery-2.1.0.js --js_output_file=jquery.closure.advanced.js and got a file of about 75K, which is smaller than jQuery's own minified version. Here is a sample of the code. Notice that it is even harder to understand than the YUI Compressor version; in advanced compilation mode, Closure changes variable and function names, inlines code, and performs several optimizations that go beyond minifying.

(function(q,W){"object"===typeof module&&"object"===typeof module.jc?module.jc=q.document?W(q,!0):function(q){if(!q.document)throw Error("jQuery requires a window with a document");return W(q)}:W(q)})("
undefined"!==typeof window?window:this,function(q,W){function ka(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)}function X(a,b){a=b||a;return"none"===d.c(a,"display")||!d.contains(a.owne
rDocument,a)}function Gb(a,b){return b.toUpperCase()}function d(a,b){return new d.b.la(a,b)}function Ba(a){var b=
a.length,c=d.type(a);return"function"===c||d.N(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"===typeof b&&0<b&&b-1 in a}function Ca(a,b,c){if(d.d(b))return d.ja(a,function(a,d){return!!b.call(a
,d,a)!==c});if(b.nodeType)return d.ja(a,function(a){return a===b!==c});if("string"===typeof b){if(Hb.test(b))return d.filter(b,a,c);b=d.filter(b,a)}return d.ja(a,function(a){return 0<=la.call(b,a)!==c})
}function Qa(a,b){for(;(a=a[b])&&1!==a.nodeType;);return a}function Ib(a){var b=Ra[a]={};d.a(a.match(H)||
[],function(a,d){b[d]=!0});return b}function ma(){s.removeEventListener("DOMContentLoaded",ma,!1);q.removeEventListener("load",ma,!1);d.B()}function L(){Object.defineProperty(this.m={},0,{get:function()
{return{}}});this.expando=d.expando+Math.random()}function Sa(a,b,c){if(void 0===c&&1===a.nodeType)if(c="data-"+b.replace(Jb,"-$1").toLowerCase(),c=a.getAttribute(c),"string"===typeof c){try{c="true"===
c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:Kb.test(c)?d.Eb(c):c}catch(f){}C.set(a,b,c)}else c=
void 0;return c}function Da(){return!0}function Y(){return!1}function Ta(){try{return s.activeElement}catch(a){}}function Ua(a,b){return d.nodeName(a,"table")&&d.nodeName(11!==b.nodeType?b:b.firstChild,
"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function Lb(a){a.type=(null!==a.getAttribute("type"))+"/"+a.type;return a}function Mb(a){var b=Nb.exec(a
.type);b?a.type=b[1]:a.removeAttribute("type");return a}function Ea(a,b){for(var c=0,d=a.length;c<
d;c++)r.set(a[c],"globalEval",!b||r.get(b[c],"globalEval"))}function Va(a,b){var c,f,e,g;if(1===b.nodeType){if(r.U(a)&&(g=r.l(a),c=r.set(b,g),g=g.ha))for(e in delete c.handle,c.ha={},g)for(c=0,f=g[e].le
ngth;c<f;c++)d.event.add(b,e,g[e][c]);C.U(a)&&(e=C.l(a),e=d.extend({},e),C.set(b,e))}}function v(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b|
|"*"):[];return void 0===b||b&&d.nodeName(a,b)?d.t([a],c):c}function Wa(a,b){var c=d(b.createElement(a)).ob(b.body),
f=q.mc?q.mc(c[0]).display:d.c(c[0],"display");c.detach();return f}function Xa(a){var b=s,c=Ya[a];c||(c=Wa(a,b),"none"!==c&&c||(T=(T||d("<iframe frameborder='0' width='0' height='0'/>")).ob(b.documentEle
ment),b=T[0].contentDocument,b.write(),b.close(),c=Wa(a,b),T.detach()),Ya[a]=c);return c}function U(a,b,c){var f,e,g=a.style;(c=c||ka(a))&&(e=c.getPropertyValue(b)||c[b]);c&&(""!==e||d.contains(a.ownerDoc [...]

By employing this kind of tool, your development team can work with clear, fully commented and indented versions of your source code, while end users get a much shorter version that's optimized for speed – a win-win situation!

Compress CSS and HTML

Your website consists not only of JavaScript, but also CSS rules and HTML code, so to round things out let's see how to compress such content. YUI Compressor, which we already looked at for JavaScript, can work with CSS files too. I got one of OpenLogic's own CSS files, which is 22K in size and about 1,400 lines long, and ran java -jar yuicompressor-2.4.8.jar wazi.css -o wazi.yui.css. That got the file down to 17K, a 25% size reduction, in a single extra long line.

.PreviewPanel{border-right:silver thin solid;border-top:silver thin solid;border-left:silver thin solid;border-bottom:silver thin solid}.linksubmission{border:solid 0 red;font:normal 11px Tahoma,Arial,V
erdana,sans-serif}.linksubmission IMG{border:solid 0 red !important}.linksubmission A{border:solid 0 red !important;text-decoration:none !important;font:normal 11px Tahoma,Arial,Verdana,sans-serif}.Grid
Header_Monochrome a:visited,.GridHeader_Monochrome a:hover{color:white !important;font:bold 11px Tahoma !important}.GridPager_Monochrome a:visited,.GridPager_Monochrome a:hover{font:normal 11px Tahoma !
important}.popupHelpTitle{padding-bottom:5px;font-weight:bold;color:black}.nostyle{border:0 solid red !important}.nostyleimg{border:0 solid red !important}.CommandItem{background-color:Transparent;backg
round-image:none}.Grid{border:1px solid #7c7c94;background-color:#fff;cursor:pointer}.HeadingRow{background-color:#e2e2e2}.HeadingCell{background-color:#e2e2e2;border:1px solid #fff;border-right-color:#
b5b5b5;border-bottom-color:#b5b5b5;padding:3px}.HeadingCellText{font-family:verdana;font-size:10px;font-weight:bold;text-align:left}.DataRow{background-color:#fff}.DataCell{cursor:default;padding:3px;bo
rder-right:1px solid #eae9e1;border-bottom:1px solid #eae9e1;font-family:verdana;font-size:10px}.EditDataCell{padding:0 !important;background-color:#e2e2e2;border-width:0 !important}.EditDataField{paddi
ng:0;padding-left:1px;font-family:verdana;font-size:10px;height:20px;width:98% !important}.DataRow td.FirstDataCell{padding-left:3px}.SelectedRow{background-color:#ffeec2}.SelectedRow td.DataCell{cursor
:default;padding:2px;padding-left:3px;padding-bottom:3px;font-family:verdana;font-size:10px;border-bottom:1px solid #4b4b6f;border-top:1px solid #4b4b6f;border-right:0}.SelectorCell{background-color:#e2
e2e2;border:1px solid #fff;border-right-color:#b5b5b5;border-bottom-color:#b5b5b5}.GridFooter{cursor:default;padding:5px}.GridFooter a{color:Black;font-weight:bold;vertical-align:bottom} [...]

I also tried two online utilities: CSS Minifier and CSS Compressor. The former can be used from the command line or as a web service by doing a POST request. The latter doesn't offer that option but includes extra optimizations, such as changing "0px" to "0," or "#FFFFFF" to "#FFF," and even "#808080" to "gray" (but "black" to "#000"!) so it goes after every possible byte to be reduced.

For HTML code, htmlcompressor can minify HTML and XML source, and is available as a command-line Java jar file for local usage. It has a large number of available options; type java -jar htmlcompressor-1.5.3.jar --help to check them out. If you are undecided as to which options use, try the -a option, which produces a nice analysis that can help indicate which command-line options you should use. I tested it with the OpenLogic HTML file I used in my deflate tests by using the command java -jar htmlcompressor-1.5.3.jar wazi.html -a. I got the following report:

================================================================================
         Setting          | Incremental Gain |    Total Gain    |  Page Size   |
================================================================================
Compression disabled      |         0 (0.0%) |         0 (0.0%) |       75,462 |
All settings disabled     |        79 (0.1%) |        79 (0.1%) |       75,383 |
Comments removed          |     2,042 (2.7%) |     2,121 (2.8%) |       73,341 |
Multiple spaces removed   |     2,492 (3.4%) |     4,613 (6.1%) |       70,849 |
No spaces between tags    |       457 (0.6%) |     5,070 (6.7%) |       70,392 |
No surround spaces (min)  |         0 (0.0%) |     5,070 (6.7%) |       70,392 |
No surround spaces (max)  |         4 (0.0%) |     5,074 (6.7%) |       70,388 |
No surround spaces (all)  |       147 (0.2%) |     5,221 (6.9%) |       70,241 |
Quotes removed from tags  |     1,101 (1.6%) |     6,322 (8.4%) |       69,140 |
<link> attr. removed      |        95 (0.1%) |     6,417 (8.5%) |       69,045 |
<style> attr. removed     |         0 (0.0%) |     6,417 (8.5%) |       69,045 |
<script> attr. removed    |       942 (1.4%) |     7,359 (9.8%) |       68,103 |
<form> attr. removed      |         0 (0.0%) |     7,359 (9.8%) |       68,103 |
<input> attr. removed     |        30 (0.0%) |     7,389 (9.8%) |       68,073 |
Simple boolean attributes |         0 (0.0%) |     7,389 (9.8%) |       68,073 |
Simple doctype            |       106 (0.2%) |     7,495 (9.9%) |       67,967 |
Remove js pseudo-protocol |         0 (0.0%) |     7,495 (9.9%) |       67,967 |
Remove http protocol      |     1,025 (1.5%) |    8,520 (11.3%) |       66,942 |
Remove https protocol     |        36 (0.1%) |    8,556 (11.3%) |       66,906 |
Compress inline CSS (YUI) |       440 (0.7%) |    8,996 (11.9%) |       66,466 |
Compress inline JS (YUI)  |     1,404 (2.1%) |   10,400 (13.8%) |       65,062 |
================================================================================

Each consecutive compressor setting is applied on top of previous ones.
In order to see JS and CSS compression results, YUI jar file must be present.
All sizes are in bytes.

Given this information, you can decide on the actual parameters to use when compressing the HTML file. A nice touch is that htmlcompressor can work with YUI Compressor or Closure, and then compress whatever JavaScript is present in your HTML, for extra savings.

I also tried out Compress HTML and HTML Compressor, two online tools. These are meant to be used online, but the latter project also offers a way to install its code as an inhouse private service; for security reasons, that seems more interesting. The code it produced is certainly more compact:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://ogp.me/ns/fb#">
<head id="Head">
<script type="text/javascript">window.hubspot={splitTimes:{preHead:new Date()}};</script>
<meta id="MetaDescription" name="description" content="Open source software technical resources discussing scanning, governance, support and more."><meta id="MetaKeywords" name="keywords" content="Open Source Articles, Open Source Tutorials, Open Source Training, Open Source Software Support"><meta id="MetaCopyright" name="copyright" content="Copyright (c) 2014"><meta id="MetaGenerator" name="generator" content="HubSpot "><meta id="MetaAuthor" name="author"><meta id="OGTitle" property="og:title" content="Wazi: Open Source Articles, Tutorials and Licensing Information"><meta id="OGUrl" property="og:url" content="http://www.openlogic.com/wazi/"><meta id="OGDescription" property="og:description" content="Open source software technical resources discussing scanning, governance, support and more."><style id="StylePlaceholder" type="text/css"></style>
<script type="text/javascript" src="/sw/website/web-all.js?v=10"></script>
<link rel="Stylesheet" href="/sw/website/web-all.css?v=10" />
<link id="_Portals__default_Skins_Duxbury_" rel="stylesheet" type="text/css" media="screen" href="/Portals/_default/Skins/Duxbury/skin.css" /><link id="PORTAL_CSS_172122" rel="stylesheet" type="text/css" media="screen" href="/Portals/172122/custom.css" /><link rel="apple-touch-icon-precomposed" media="screen" href="/Portals/172122/images/iOS-57px.png" /><link rel="apple-touch-icon-precomposed" sizes="72X72" media="screen" href="/Portals/172122/images/iOS-72px.png" />
<!--[if IE]>
<link href="/Portals/172122/PIE-HTC/ie.css" rel="stylesheet" type="text/css" />
<![endif]--> [...]

The compressed HTML code is about 10% shorter.

Note that with all these tools, if your site's HTML code is generated by a script, a compressor won't be able to compress it effectively.

In conclusion

As you can see, you can take advantage of several ways to reduce file sizes and in effect speed up your web server. The sum of all compression functions – server, JavaScript, CSS, and HTML – produces smaller data transmissions and faster response times. Apply them, and your users will thank you for it!


Do you want to receive a compilation of Wazi's top
blog posts in the past year delivered directly to your inbox?






This work is licensed under a Creative Commons Attribution 3.0 Unported License
Creative Commons License.

Comments

I already have bought this pancakes recipes, these are well easy recipes to make pancakes, i may try that soon.
Posted @ Friday, April 04, 2014 3:00 PM by reliable dissertation in uk
 
 
 
If you are a die-hard passionate for Cheap Replica Handbags, the right choice is definitely our Repliques rolex. Some look very basic and others very elegant and luxurious, some are made with Replica designer handbags materials and designs and others with simple but beautiful designs. The delicate pleating of the perforated patent leather imparts the Replica Shoes a feminine charm. For instance, high quality Replica Watches make use of soft leather and good quality hardware.  
 
Posted @ Friday, June 06, 2014 10:08 PM by kenny
Numerous wholesalers and also fake omega watches have got launched out there for the world wide web being a destination for a offer you awesome bargains with chin falling rates. How much organizations supplying these kinds of hublot replica watches will be improving with a stunning fee, which can be remarkable to suit your needs the buyer. Lowering your rates expense regarding artist bags and also bag vendors is now less difficult as compared to any moment before. The particular replica chanel compared to that is not any. Definitely not necessarily. It really is thus generally in the direction of the particular computer chip chemical attain out there manoeuvre compared to that connection inside your wander relationship in the direction of the actual fact right now there really really certainly are a great add regarding improved any time inside diverse together with web retailers swiftly useful industry attract next to in the direction of the particular fake gucci which usually occur directing obtaining aim right now there to be able to bully money just before approach inside of regarding relationship. Inside your method replica chanel handbags sale in the direction of the particular probable deducted buyers by means of asking increased charges or perhaps through offering forge shoes or boots.
Posted @ Friday, August 22, 2014 1:20 AM by guanwei
Post Comment
Name
 *
Email
 *
Website (optional)
Comment
 *

Allowed tags: <a> link, <b> bold, <i> italics