<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Slash Dot Dash: Rails performance tip - using YSlow</title>
    <link>http://www.slashdotdash.net/articles/2007/07/31/rails-performance-tip-using-yslow</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Rolling on Rails</description>
    <item>
      <title>Rails performance tip - using YSlow</title>
      <description>&lt;p&gt;YSlow from Yahoo! is a &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/5369"&gt;Firefox add-on&lt;/a&gt; to &lt;em&gt;analyse web pages and tell you why they&amp;#8217;re slow based on&lt;/em&gt; &lt;a href="http://developer.yahoo.com/performance/index.html#rules"&gt;rules for high performance web sites&lt;/a&gt;. YSlow requires the indispensable Firebug extension.&lt;/p&gt;


	&lt;p&gt;The 13 rules YSlow checks your site against are as follows:&lt;/p&gt;


	&lt;pre&gt;&lt;code&gt;1. Make Fewer HTTP Requests
2. Use a Content Delivery Network
3. Add an Expires Header
4. Gzip Components
5. Put CSS at the Top
6. Move Scripts to the Bottom
7. Avoid CSS Expressions
8. Make JavaScript and CSS External
9. Reduce DNS Lookups
10. Minify JavaScript
11. Avoid Redirects
12. Remove Duplicate Scripts
13. Configure ETags&lt;/code&gt;&lt;/pre&gt;


	&lt;p&gt;This post will demonstrate that most of these are easily achievable for a Rails website through a combination of plugins and with correct configuration of a proxy web server (in front of a mongrel cluster) &amp;#8211; in this case &lt;a href="http://wiki.codemongers.com/Nginx"&gt;Nginx&lt;/a&gt;. This guide follows experience with improving performance for &lt;a href="http://www.trawlr.com"&gt;trawlr.com&lt;/a&gt; (an online &lt;span class="caps"&gt;RSS&lt;/span&gt; reader).&lt;/p&gt;


	&lt;h2&gt;Make Fewer &lt;span class="caps"&gt;HTTP&lt;/span&gt; Requests, Minify JavaScript, Put &lt;span class="caps"&gt;CSS&lt;/span&gt; at the Top, Move Scripts to the Bottom, Remove Duplicate Scripts&lt;/h2&gt;


	&lt;p&gt;The easiest way to make fewer &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests is to combine all JavaScript and &lt;span class="caps"&gt;CSS&lt;/span&gt; files into one. The &lt;a href="http://synthesis.sbecker.net/pages/asset_packager"&gt;asset packager&lt;/a&gt; plugin does exactly this, plus it will also compress the source files (in production mode) and correctly handles caching (without query string parameters).&lt;/p&gt;


	&lt;p&gt;Moving &lt;span class="caps"&gt;CSS&lt;/span&gt; to the top (within the head section) and moving JavaScript to the bottom of the page are both manual tasks that should be done in the layout templates (such as &lt;code&gt;app/views/layouts/application.rhtml&lt;/code&gt;). Remember to use &lt;code&gt;stylesheet_link_merged :base&lt;/code&gt; and &lt;code&gt;javascript_include_merged :base&lt;/code&gt; rather than the default Rails helpers.&lt;/p&gt;


	&lt;p&gt;By using asset packager you can also verify that scripts are only included once &amp;#8211; another performance hit otherwise!&lt;/p&gt;


	&lt;p&gt;Excluding the Google analytics JavaScript file, trawlr.com now uses a single css and js file (including the entire prototype library). Note: You may need to add a missing semi-colon as per this &lt;a href="http://dev.rubyonrails.org/ticket/7301"&gt;defect&lt;/a&gt; for prototype to work correctly.&lt;/p&gt;


	&lt;p&gt;Asset Packager can be included as part of a Capistrano deployment with the following recipe:&lt;/p&gt;


&lt;pre&gt;
desc "Compress JavaScript and CSS files using asset_packager" 
task :after_update_code, :roles =&amp;gt; [:web] do
  run &amp;lt;&amp;lt;-EOF
    cd #{release_path} &amp;#38;&amp;#38;
    rake RAILS_ENV=production asset:packager:build_all
  EOF
end
&lt;/pre&gt;

	&lt;h2&gt;Use a Content Delivery Network&lt;/h2&gt;


	&lt;p&gt;Ignoring this point for now; I&amp;#8217;d suggest the use of Amazon S3 as a useful starting point for simple &lt;span class="caps"&gt;CDN&lt;/span&gt;.&lt;/p&gt;


	&lt;h2&gt;Add an Expires Header&lt;/h2&gt;


	&lt;blockquote&gt;
		&lt;p&gt;A first-time visitor to your page may have to make several &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests, but by using the Expires header you make those components cacheable. This avoids unnecessary &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests on subsequent page views. Expires headers are most often used with images, but they should be used on all components including scripts, stylesheets, and Flash components.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;Nginx allows adding arbitrary &lt;span class="caps"&gt;HTTP&lt;/span&gt; headers via the &lt;code&gt;expire&lt;/code&gt; and &lt;code&gt;add_header&lt;/code&gt; directives. Adding the expires header to static content is done with a regular expression looking for relevant file extensions in the request &lt;span class="caps"&gt;URL&lt;/span&gt;. This example uses the maximum expiry date but could be set to more appropriate values as required (e.g. 24h, 7d, 1M)&lt;/p&gt;


&lt;pre&gt;
# Add expires header for static content
location ~* \.(js|css|jpg|jpeg|gif|png)$ {
  if (-f $request_filename) {
        expires      max;
    break; 
  }        
}
&lt;/pre&gt;

	&lt;h2&gt;Gzip Components&lt;/h2&gt;


	&lt;p&gt;Nginx can gzip any responses &amp;#8211; including those proxied from a mongrel cluster.&lt;/p&gt;


&lt;pre&gt;
gzip on;
gzip_min_length  1100;
gzip_buffers     4 8k;
gzip_proxied any;              
gzip_types  text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
&lt;/pre&gt;

	&lt;h2&gt;Avoid &lt;span class="caps"&gt;CSS&lt;/span&gt; Expressions&lt;/h2&gt;


	&lt;p&gt;Just don&amp;#8217;t do it!&lt;/p&gt;


	&lt;h2&gt;Make JavaScript and &lt;span class="caps"&gt;CSS&lt;/span&gt; External&lt;/h2&gt;


	&lt;p&gt;Add you JavaScript and &lt;span class="caps"&gt;CSS&lt;/span&gt; styles in external files rather than inline. The added benefit here is that the content will be merged and compressed thanks to the work already done above.&lt;/p&gt;


	&lt;h2&gt;Reduce &lt;span class="caps"&gt;DNS&lt;/span&gt; Lookups, Avoid Redirects, Configure ETags&lt;/h2&gt;


	&lt;p&gt;These weren&amp;#8217;t an issue for me so I suggest the Yahoo! guidance for further information&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://developer.yahoo.com/performance/rules.html#dns_lookups"&gt;Reduce &lt;span class="caps"&gt;DNS&lt;/span&gt; Lookups&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://developer.yahoo.com/performance/rules.html#redirects"&gt;Avoid Redirects&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href="http://developer.yahoo.com/performance/rules.html#etags"&gt;Configure ETags&lt;/a&gt;&lt;/p&gt;


	&lt;h2&gt;Summary&lt;/h2&gt;


	&lt;p&gt;After making the changes outlined above the YSlow score for &lt;a href="http://www.trawlr.com/"&gt;trawlr.com&lt;/a&gt; has hit a B grade (89) with all points A grade except &amp;#8220;Use a &lt;span class="caps"&gt;CDN&lt;/span&gt;&amp;#8221; which I have not addressed. The &amp;#8220;Stats&amp;#8221; view indicates that with an empty browser cache there would be 30 &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests (26.0K total size), with a full cache this drops to a single request (the &lt;span class="caps"&gt;HTML&lt;/span&gt; document) (6.5K total size). Worth the effort in my opinion!&lt;/p&gt;</description>
      <pubDate>Tue, 31 Jul 2007 21:50:18 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:3df84e4e-f6b7-4344-97a0-d7cc04c756b2</guid>
      <author>ben@slashdotdash.net (Ben)</author>
      <link>http://www.slashdotdash.net/articles/2007/07/31/rails-performance-tip-using-yslow</link>
      <category>Ruby on Rails</category>
    </item>
    <item>
      <title>"Rails performance tip - using YSlow" by Matt</title>
      <description>&lt;p&gt;The expires header command doesn&amp;#8217;t seem to be working (at least for me).   And if I add the simpler expire:
if (-f $request_filename) {
expires 10y;
break;
}&lt;/p&gt;


	&lt;p&gt;YSlow still complains that my static assets have no expires headers.  Any thoughts?&lt;/p&gt;</description>
      <pubDate>Tue, 25 Dec 2007 23:01:21 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:66f78a08-89d7-4890-b584-ee98e281a0ea</guid>
      <link>http://www.slashdotdash.net/articles/2007/07/31/rails-performance-tip-using-yslow#comment-320</link>
    </item>
    <item>
      <title>"Rails performance tip - using YSlow" by Tom</title>
      <description>&lt;p&gt;One bit about ETags which I initially found quite confusing &amp;#8211; YSlow is actually going to penalize you for &lt;strong&gt;using&lt;/strong&gt; them, not for omitting them.  The point they&amp;#8217;re trying to make is that unless you&amp;#8217;re using a cluster of servers, making use of ETags to detect file changes is unnecessary overhead.&lt;/p&gt;


	&lt;p&gt;If you do use multiple servers though, the Apache directive to do this correctly is:&lt;/p&gt;


	&lt;p&gt;FileETag MTime Size&lt;/p&gt;


	&lt;p&gt;This prevents apache from using inode information in it&amp;#8217;s etag calculation (which, for us rails users, is going to change on every run of capistrano).&lt;/p&gt;


	&lt;p&gt;For more details, I found this blog post very helpful:
&lt;a href="http://phaedo.cx/archives/2007/07/25/tools-for-optimizing-your-website-etag-and-expire-headers-in-django-apache-and-lighttpd/" rel="nofollow"&gt;http://phaedo.cx/archives/2007/07/25/tools-for-optimizing-your-website-etag-and-expire-headers-in-django-apache-and-lighttpd/&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Fri, 10 Aug 2007 18:22:32 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:c3bd40da-91b8-4253-b233-385857f99ea8</guid>
      <link>http://www.slashdotdash.net/articles/2007/07/31/rails-performance-tip-using-yslow#comment-128</link>
    </item>
    <item>
      <title>"Rails performance tip - using YSlow" by casual</title>
      <description>&lt;p&gt;I&amp;#8217;d have to agree with all of this except the comment about javascript. As a front end developer, it&amp;#8217;s generally bad practice to have javascript anywhere but in the HEAD of a document.&lt;/p&gt;</description>
      <pubDate>Thu, 09 Aug 2007 23:53:16 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:edf61864-1093-4c86-a630-3e8e7225edd2</guid>
      <link>http://www.slashdotdash.net/articles/2007/07/31/rails-performance-tip-using-yslow#comment-127</link>
    </item>
    <item>
      <title>"Rails performance tip - using YSlow" by Fnor</title>
      <description>&lt;p&gt;Thanks for your YSlow presentation. It&amp;#8217;s a very interesting tool to improve websites speed.&lt;/p&gt;


	&lt;p&gt;Regarding the number of HTTP connections due to lots of small images, I recommend reading : &lt;a href="http://www.alistapart.com/articles/sprites/" rel="nofollow"&gt;http://www.alistapart.com/articles/sprites/&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Thu, 09 Aug 2007 13:38:01 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:7cebc172-ecf9-4df0-abbf-6d3d625d757b</guid>
      <link>http://www.slashdotdash.net/articles/2007/07/31/rails-performance-tip-using-yslow#comment-126</link>
    </item>
    <item>
      <title>"Rails performance tip - using YSlow" by Ben</title>
      <description>&lt;p&gt;@The Smartass Who Ran YSlow on This Site&lt;/p&gt;


	&lt;p&gt;Ha, I never even tried it on this site&amp;#8230; I&amp;#8217;m in the process of upgrading to the latest version of Typo (along with a new design) so I&amp;#8217;ll see if I can up that number :-)&lt;/p&gt;</description>
      <pubDate>Thu, 09 Aug 2007 07:37:49 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:a5d1c114-16be-455a-934e-988e7a038460</guid>
      <link>http://www.slashdotdash.net/articles/2007/07/31/rails-performance-tip-using-yslow#comment-125</link>
    </item>
    <item>
      <title>"Rails performance tip - using YSlow" by Jake Stetser</title>
      <description>&lt;p&gt;Technically, you can &amp;#8216;cheat&amp;#8217; with the CDN rule &amp;#8211; if you spread your accesses out over several domains (with something like asset_hosts), there&amp;#8217;s an about:config setting in which you can list your own domains for the CDN.&lt;/p&gt;


	&lt;p&gt;I did that for now since I think only akamai and yahoo are currently listed in their CDN list.&lt;/p&gt;</description>
      <pubDate>Wed, 01 Aug 2007 15:29:38 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:9cc02393-6465-47b3-9788-279cdb033d4e</guid>
      <link>http://www.slashdotdash.net/articles/2007/07/31/rails-performance-tip-using-yslow#comment-119</link>
    </item>
    <item>
      <title>"Rails performance tip - using YSlow" by Paul M. Watson</title>
      <description>&lt;p&gt;Thanks, good guide.&lt;/p&gt;


	&lt;p&gt;On the CDN front I am pretty sure S3 isn&amp;#8217;t a CDN as it is at most in two locations. Hopefully S3 starts offering a CDN option though.&lt;/p&gt;</description>
      <pubDate>Wed, 01 Aug 2007 05:57:08 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:a9d9c313-b1f0-40ac-8992-498ef3112094</guid>
      <link>http://www.slashdotdash.net/articles/2007/07/31/rails-performance-tip-using-yslow#comment-118</link>
    </item>
  </channel>
</rss>
