Faster Sites Done Faster
Wow! This takes me back! Please check the date this post was authored, as it may no longer be relevant in a modern context.
Google wants your site to be faster. They want it so much, they made videos! You don’t want to watch videos though, you want to make your site faster, faster. Take an hour of time and make your website 4-5x faster using these 5 high-impact techniques:
- Set HTTP Cache Headers
- Gzip Web Server Output
- Use Multiple, Cookie-less Domains for Assets
- Bundle Javascript & CSS
- Crush Image Assets
I’m going to use Rails for these examples, but you should have something comparable in any web framework. Rails got a bad rap on speed for a long time, but where the server-side code failed, the architecture won. HTTP and Rails are already in bed together, here’s how to join in.
Set HTTP Cache Headers
HTTP is your friend. Rails already handles adding timestamps to your assets URLs (that’s the ?19438273834
after the image URI. That’s why you always use image_tag), but you need to set up the HTTP headers yourself. In Apache 2 this looks like:
<VirtualHost *:80>
# Your config...
ExpiresActive On
<FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
ExpiresDefault "access plus 1 year"
Header unset ETag
FileETag None
Header unset Last-Modified
</FilesMatch>
</VirtualHost>
In Nginx:
server {
# Your config...
location ~* (css|js|png|jpe?g|gif|ico)$ {
expires max;
}
}
A warning to the wise- this works fairly seamlessly under Rails, but if you are on another framework be sure you have some kind of rolling argument to assets for new deploys. If not, the expires max
will mean browsers will not try to pull down the new content you just deployed.
Gzip Web Server Output
Web pages, Javascript, and CSS are all text, and compress very nicely under gzip. This is a no-brainer to turn on, and it will have an immediate impact on your site. In Apache 2:
<VirtualHost *:80>
# Your config...
AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml text/javascript text/css application/x-javascript
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \\bMSIE !no-gzip !gzip-only-text/html
</VirtualHost>
In Nginx:
server {
# Your config...
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/xml text/css application/javascript;
gzip_disable msie6;
}
Both of these configurations bypass IE6. That’s a darn shame, if only we could make IE6 load pages faster somehow…liiike….
Use Multiple, Cookie-less Domains for Assets
This technique requires you to update your DNS entries, but it is well worth the effort. There are 2 Rails-side parts to this. One is to always use image_tag
, javascript_include_tag
, etc. Don’t write your own tags. Then update your asset_host
configuration:
# In config/environments/production.rb
ActionController::Base.asset_host = Proc.new { |source, request|
if request and request.ssl?
"https://www" # Just use one domain during SSL. This avoids mixed content errors.
else
"http://www#{source.hash % 4}"
end + ".coolapp.com"
}
Now configure A records for each asset domain:
www0.coolsite.com 12.34.56.78
www1.coolsite.com 12.34.56.78
www2.coolsite.com 12.34.56.78
www3.coolsite.com 12.34.56.78
Lastly, configure your server. The basic configuration (again, Apache 2):
<VirtualHost *:80>
ServerName www.coolsite.com
ServerAlias www0.coolsite.com
ServerAlias www1.coolsite.com
ServerAlias www2.coolsite.com
ServerAlias www3.coolsite.com
# rewrite rules, etc
</VirtualHost *:80>
Of course, that leaves the whole app available on any of those domains. We can use a require condition before routing to the app so only the assets are available:
<VirtualHost *:80>
ServerName www.coolsite.com
ServerAlias www0.coolsite.com
ServerAlias www1.coolsite.com
ServerAlias www2.coolsite.com
ServerAlias www3.coolsite.com
# other config...
# Redirect all non-static requests to cluster
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{HTTP_HOST} ^www.coolsite.com$ # Only if they are asking for www
RewriteRule ^/(.*)$ balancer://coolsite_cluster%{REQUEST_URI} [P,QSA,L]
</VirtualHost *:80>
Set up multiple asset hosts now! If you have not done it, this is the most important technique on this page. It will make your website 3-4 times faster in most browsers. Yes, even Firefox will feel faster. Go, do it!
Bundle Javascript & CSS
Fewer downloads means less wait time for the browser. Bundle your Javascript and CSS into a single file for production. Super easy in Rails:
<%= javascript_include_tag 'mootools.js', 'lightbox.js', 'application.js', :cache => 'cache-application' %>
<%= stylesheet_link_tag 'lightbox.css', 'application.css' :cache => 'cache-application' %>
Crush Image Assets
Ok, this is the hardest thing on this list, and my example is the most Rails specific yet. You will need to install two applications: pngcrush and jpegtran. Both were easily installable in Gentoo, so check Ports or Apt or what-have-you. Now add this file to your project:
# lib/tasks/assets.rake
namespace :assets do
desc "Crush png images"
task :crush_pngs do
Dir['public/**/*.png'].each do |file|
`pngcrush -rem alla -reduce -brute "#{file}" "#{file}.crushing"`
`mv "#{file}.crushing" "#{file}"`
end
end
desc "Crush jp(e)g images"
task :crush_jpgs do
( Dir['public/**/*.jpg'] + Dir['public/**/*.jpeg'] ).each do |file|
`jpegtran -copy none -optimize -perfect -outfile "#{file}.crushing" "#{file}"`
`mv "#{file}.crushing" "#{file}"`
end
end
desc "Crush images"
task :crush_images do
%w( assets:crush_pngs assets:crush_jpgs ).each do |task|
Rake::Task[task].invoke
end
end
end
Now you can
rake assets:crush_images
Review the changes, commit and push it live. These utilities are loss-less; They only strip fatty metadata not needed by browsers. Run it every time you make a large number of image changes.
Be Fast & Prove It
Before you start using these techniques, check out Firebug, Yslow, and Google Page Speed. Run the excellent IE focused WebPagetest. Gather some hard numbers before you make a change, then do some follow-up tests. Be amazed. Be fast. Get back to building your great site.
Do you have a dead simple, quick and high-impact web technique? Share it with us!