Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 6161

Show
Ignore:
Timestamp:
02/18/07 06:44:20 (2 years ago)
Author:
bitsweat
Message:

Work around the two connection per host browser limit: use asset%d.myapp.com to distribute asset requests among asset[0123].myapp.com. Use a DNS wildcard or CNAMEs to map these hosts to your asset server. See http://www.die.net/musings/page_load_time/ for background.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/actionpack/CHANGELOG

    r6159 r6161  
    11*SVN* 
     2 
     3* Work around the two connection per host browser limit: use asset%d.myapp.com to distribute asset requests among asset[0123].myapp.com. Use a DNS wildcard or CNAMEs to map these hosts to your asset server. See http://www.die.net/musings/page_load_time/ for background.  [Jeremy Kemper] 
    24 
    35* Added default mime type for CSS (Mime::CSS) [DHH] 
  • trunk/actionpack/lib/action_view/helpers/asset_tag_helper.rb

    r6057 r6161  
    1212    # 
    1313    #   ActionController::Base.asset_host = "http://assets.example.com" 
    14     #   image_tag("rails.png")   
     14    #   image_tag("rails.png") 
    1515    #     => <img src="http://assets.example.com/images/rails.png" alt="Rails" /> 
    1616    #   stylesheet_include_tag("application") 
    1717    #     => <link href="http://assets.example.com/stylesheets/application.css" media="screen" rel="Stylesheet" type="text/css" /> 
     18    # 
     19    # Since browsers typically open at most two connections to a single host, 
     20    # your assets often wait in single file for their turn to load. 
     21    # 
     22    # Use a %d wildcard in asset_host (asset%d.myapp.com) to automatically 
     23    # distribute asset requests among four hosts (asset0-asset3.myapp.com) 
     24    # so browsers will open eight connections rather than two.  Use wildcard 
     25    # DNS to CNAME the wildcard to your real asset host. 
     26    # 
     27    # Note: this is purely a browser performance optimization and is not meant 
     28    # for server load balancing. See http://www.die.net/musings/page_load_time/ 
     29    # for background. 
    1830    module AssetTagHelper 
    1931      # Returns a link tag that browsers and news readers can use to auto-detect 
    20       # an RSS or ATOM feed. The +type+ can either be <tt>:rss</tt> (default) or  
     32      # an RSS or ATOM feed. The +type+ can either be <tt>:rss</tt> (default) or 
    2133      # <tt>:atom</tt>. Control the link options in url_for format using the 
    2234      # +url_options+. You can modify the LINK tag itself in +tag_options+. 
     
    3749      def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {}) 
    3850        tag( 
    39           "link",  
     51          "link", 
    4052          "rel"   => tag_options[:rel] || "alternate", 
    4153          "type"  => tag_options[:type] || Mime::Type.lookup_by_extension(type.to_s).to_s, 
     
    5466      #   javascript_path "/dir/xmlhr" # => /dir/xmlhr.js 
    5567      def javascript_path(source) 
    56         compute_public_path(source, 'javascripts', 'js')         
     68        compute_public_path(source, 'javascripts', 'js') 
    5769      end 
    5870 
     
    6577      # current page or you can pass the full path relative to your document 
    6678      # root. To include the Prototype and Scriptaculous javascript libraries in 
    67       # your application, pass <tt>:defaults</tt> as the source. When using  
    68       # :defaults, if an <tt>application.js</tt> file exists in your public  
    69       # javascripts directory, it will be included as well. You can modify the  
    70       # html attributes of the script tag by passing a hash as the last argument.  
     79      # your application, pass <tt>:defaults</tt> as the source. When using 
     80      # :defaults, if an <tt>application.js</tt> file exists in your public 
     81      # javascripts directory, it will be included as well. You can modify the 
     82      # html attributes of the script tag by passing a hash as the last argument. 
    7183      # 
    7284      #   javascript_include_tag "xmlhr" # => 
     
    8597        options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { } 
    8698 
    87         if sources.include?(:defaults)  
    88           sources = sources[0..(sources.index(:defaults))] +  
    89             @@javascript_default_sources.dup +  
     99        if sources.include?(:defaults) 
     100          sources = sources[0..(sources.index(:defaults))] + 
     101            @@javascript_default_sources.dup + 
    90102            sources[(sources.index(:defaults) + 1)..sources.length] 
    91103 
    92           sources.delete(:defaults)  
    93           sources << "application" if defined?(RAILS_ROOT) && File.exists?("#{RAILS_ROOT}/public/javascripts/application.js")  
     104          sources.delete(:defaults) 
     105          sources << "application" if defined?(RAILS_ROOT) && File.exists?("#{RAILS_ROOT}/public/javascripts/application.js") 
    94106        end 
    95107 
    96108        sources.collect do |source| 
    97           source = javascript_path(source)         
     109          source = javascript_path(source) 
    98110          content_tag("script", "", { "type" => "text/javascript", "src" => source }.merge(options)) 
    99111        end.join("\n") 
    100112      end 
    101        
     113 
    102114      # Register one or more additional JavaScript files to be included when 
    103115      # <tt>javascript_include_tag :defaults</tt> is called. This method is 
    104       # only intended to be called from plugin initialization to register additional  
     116      # only intended to be called from plugin initialization to register additional 
    105117      # .js files that the plugin installed in <tt>public/javascripts</tt>. 
    106118      def self.register_javascript_include_default(*sources) 
    107119        @@javascript_default_sources.concat(sources) 
    108120      end 
    109        
     121 
    110122      def self.reset_javascript_include_default #:nodoc: 
    111123        @@javascript_default_sources = JAVASCRIPT_DEFAULT_SOURCES.dup 
     
    166178 
    167179      # Returns an html image tag for the +source+. The +source+ can be a full 
    168       # path or a file that exists in your public images directory. Note that  
     180      # path or a file that exists in your public images directory. Note that 
    169181      # specifying a filename without the extension is now deprecated in Rails. 
    170182      # You can add html attributes using the +options+. The +options+ supports 
    171183      # two additional keys for convienence and conformance: 
    172184      # 
    173       # * <tt>:alt</tt>  - If no alt text is given, the file name part of the  
     185      # * <tt>:alt</tt>  - If no alt text is given, the file name part of the 
    174186      #   +source+ is used (capitalized and without the extension) 
    175       # * <tt>:size</tt> - Supplied as "{Width}x{Height}", so "30x45" becomes  
     187      # * <tt>:size</tt> - Supplied as "{Width}x{Height}", so "30x45" becomes 
    176188      #   width="30" and height="45". <tt>:size</tt> will be ignored if the 
    177189      #   value is not in the correct format. 
     
    185197      def image_tag(source, options = {}) 
    186198        options.symbolize_keys! 
    187                  
     199 
    188200        options[:src] = image_path(source) 
    189201        options[:alt] ||= File.basename(options[:src], '.*').split('.').first.capitalize 
    190          
     202 
    191203        if options[:size] 
    192204          options[:width], options[:height] = options[:size].split("x") if options[:size] =~ %r{^\d+x\d+$} 
     
    196208        tag("img", options) 
    197209      end 
    198        
     210 
    199211      private 
     212        # Add the .ext if not present. Return full URLs otherwise untouched. 
     213        # Prefix with /dir/ if lacking a leading /. Account for relative URL 
     214        # roots. Rewrite the asset path for cache-busting asset ids. Include 
     215        # a single or wildcarded asset host if configured. 
    200216        def compute_public_path(source, dir, ext) 
    201           source = source.dup 
    202           source << ".#{ext}" if File.extname(source).blank? 
    203           unless source =~ %r{^[-a-z]+://} 
     217          source += ".#{ext}" if File.extname(source).blank? 
     218          if source =~ %r{^[-a-z]+://} 
     219            source 
     220          else 
    204221            source = "/#{dir}/#{source}" unless source[0] == ?/ 
    205             asset_id = rails_asset_id(source) 
    206             source << '?' + asset_id if defined?(RAILS_ROOT) && !asset_id.blank? 
    207             source = "#{ActionController::Base.asset_host}#{@controller.request.relative_url_root}#{source}" 
     222            source = "#{@controller.request.relative_url_root}#{source}" 
     223            rewrite_asset_path!(source) 
     224            "#{compute_asset_host(source)}#{source}" 
    208225          end 
    209           source 
    210         end 
    211          
     226        end 
     227 
     228        # Pick an asset host for this source. Returns nil if no host is set, 
     229        # the host if no wildcard is set, or the host interpolated with the 
     230        # numbers 0-3 if it contains %d. The number is the source hash mod 4. 
     231        def compute_asset_host(source) 
     232          if host = ActionController::Base.asset_host 
     233            host % (source.hash % 4) 
     234          end 
     235        end 
     236 
     237        # Use the RAILS_ASSET_ID environment variable or the source's 
     238        # modification time as its cache-busting asset id. 
    212239        def rails_asset_id(source) 
    213           ENV["RAILS_ASSET_ID"] ||  
     240          ENV["RAILS_ASSET_ID"] || 
    214241            File.mtime("#{RAILS_ROOT}/public/#{source}").to_i.to_s rescue "" 
     242        end 
     243 
     244        # Break out the asset path rewrite so you wish to put the asset id 
     245        # someplace other than the query string. 
     246        def rewrite_asset_path!(source) 
     247          asset_id = rails_asset_id(source) 
     248          source << "?#{asset_id}" if defined?(RAILS_ROOT) && !asset_id.blank? 
    215249        end 
    216250    end 
  • trunk/actionpack/test/template/asset_tag_helper_test.rb

    r6057 r6161  
    224224    ActionController::Base.asset_host = "" 
    225225  end 
     226 
     227  def test_should_wildcard_asset_host_between_zero_and_four 
     228    ActionController::Base.asset_host = 'http://a%d.example.com' 
     229    assert_match %r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_path('xml.png') 
     230  ensure 
     231    ActionController::Base.asset_host = nil 
     232  end 
    226233end