SlideShare a Scribd company logo
Sprockets
 You’ve got tons of JavaScript.
Time to do something about it.


     Christophe Porteneuve
        JSConf.eu 2009
Hi, I’m Christophe

• I’m 32 and I live in Paris, France
• I use Rails all day at work
• I’m a Prototype Core member
• I wrote Prototype and script.aculo.us
  (“The Bungee Book”)
• I’m glad to be here!
The problem
The problem

• JavaScript is the next big language…
The problem

• JavaScript is the next big language…
• It’s already getting big, codewise!
The problem

• JavaScript is the next big language…
• It’s already getting big, codewise!
• Many apps have countless JS files
The problem

• JavaScript is the next big language…
• It’s already getting big, codewise!
• Many apps have countless JS files
• Loading → lots of requests → latence
The problem

• JavaScript is the next big language…
• It’s already getting big, codewise!
• Many apps have countless JS files
• Loading → lots of requests → latence
• Or you could maintain one big file…
The problem

• JavaScript is the next big language…
• It’s already getting big, codewise!
• Many apps have countless JS files
• Loading → lots of requests → latence
• Or you could maintain one big file…
• …which sucks
The solution
The solution

• You want to split your JS code in neat files
  and folders!
The solution

• You want to split your JS code in neat files
  and folders!
• You want some structure, dammit!
The solution

• You want to split your JS code in neat files
  and folders!
• You want some structure, dammit!
• But you want to serve just one file!
The solution

• You want to split your JS code in neat files
  and folders!
• You want some structure, dammit!
• But you want to serve just one file!
• Enter Sprockets
So many cool things…
So many cool things…

• Use require directives and load paths to
  structure your source
So many cool things…

• Use require directives and load paths to
  structure your source

• Preprocess constants!
So many cool things…

• Use require directives and load paths to
  structure your source

• Preprocess constants!
• Create “JS plugins,” complete with related
  CSS/image assets, bundle them and
  distribute them easily
Getting organized
Getting organized




        …
        //= require "lang"
        //= require "ajax"
        //= require "dom"
Getting organized



        //=   require   "dom/dom"
        //=   require   "dom/selector"
        //=   require   "dom/form"
        //=   require   "dom/event"

        Element.addMethods();



        …
        //= require "lang"
        //= require "ajax"
        //= require "dom"
Getting organized
        //=   require   "ajax/ajax"
        //=   require   "ajax/responders"
        //=   require   "ajax/base"
        //=   require   "ajax/request"
        //=   require   "ajax/response"
        //=   require   "ajax/updater"
        //=   require   "ajax/periodical_updater"



        //=   require   "dom/dom"
        //=   require   "dom/selector"
        //=   require   "dom/form"
        //=   require   "dom/event"

        Element.addMethods();



        …
        //= require "lang"
        //= require "ajax"
        //= require "dom"
The load path
Sprockets has a load path, much like C’s or
Ruby’s
The load path
Sprockets has a load path, much like C’s or
Ruby’s

Using the load path:
         //= require <coolobj>
         //= require <coollib/coolobj>
The load path
Sprockets has a load path, much like C’s or
Ruby’s

Using the load path:
          //= require <coolobj>
          //= require <coollib/coolobj>




Using paths relative to the current file:
          //= require "coolobj"
          //= require "subdir/coolobj"
Constants FTW!

Put a constants.yml file somewhere in your
load path
• It’s a YAML file
• Heard of YAML, right?
• Super simple yet powerful
Constants for you
Constants for you
Constants for you


        PROTOTYPE_VERSION: 1.6.1_rc3
Constants for you


        PROTOTYPE_VERSION: 1.6.1_rc3




        var Prototype = {
          Version: '<%= PROTOTYPE_VERSION %>',

         Browser: (function(){
           …
Bundling assets


                         //= require "color"
                         //= provide "../assets"




    Because you require <color_picker>,
Sprockets can copy the assets to your asset root
   (somewhere inside your document root)
I can haz?

• It’s a Ruby gem
• You don’t need to know Ruby though
• You do need Ruby and Rubygems installed
I can haz?

    • It’s a Ruby gem
    • You don’t need to know Ruby though
    • You do need Ruby and Rubygems installed
$ sudo gem install --remote sprockets
As a command-line tool…

$ sprocketize
Usage: sprocketize [options] filename [filename ...]
    -C, --directory=DIRECTORY        Change to DIRECTORY before doing anything
    -I, --include-dir=DIRECTORY      Adds the directory to the Sprockets load path
    -a, --asset-root=DIRECTORY       Copy provided assets into DIRECTORY
    …
    -h, --help                       Shows this help message
    -v, --version                    Shows version
As a command-line tool…

$ sprocketize
Usage: sprocketize [options] filename [filename ...]
    -C, --directory=DIRECTORY        Change to DIRECTORY before doing anything
    -I, --include-dir=DIRECTORY      Adds the directory to the Sprockets load path
    -a, --asset-root=DIRECTORY       Copy provided assets into DIRECTORY
    …
    -h, --help                       Shows this help message
    -v, --version                    Shows version




$ sprocketize -I src -a dist src/application.js > dist/javascripts/application.js
Within Ruby code…
Within Ruby code…

require 'rubygems'
require 'sprockets'

secretary = Sprockets::Secretary.new(
  :asset_root   => "public",
  :load_path    => ["vendor/sprockets/*/src", "vendor/plugins/*/javascripts"],
  :source_files => ["app/javascripts/application.js", "app/javascripts/**/*.js"]
)

concatenation = secretary.concatenation
concatenation.save_to("public/sprockets.js")
secretary.install_assets
As a CGI script…
         Say you have this tree
As a CGI script…
         Say you have this tree

         :load_path:
           - javascripts
           - vendor/sprockets/*/src
         :source_files:
           - javascripts/mysite.js
           - javascripts/*.js
         :output_file: public/sprockets.js




            So you write this
            sprockets.yml
As a CGI script…
<VirtualHost *:80>
  ServerName www.sprocketsrule.com
  DocumentRoot "/var/webapps/sprocketsrule/public"

  <Directory "/var/webapps/sprocketsrule/public">
    Options +ExecCGI +FollowSymLinks
    AddHandler cgi-script .cgi

    RewriteEngine on
    RewriteCond /sprockets.js !-f
    RewriteRule ^sprockets.js /nph-sprockets.cgi [P,L]
    SetEnv sprockets_generate_output_file true
  </Directory>
</VirtualHost>




<script type="text/javascript" src="/sprockets.js"></script>
As a CGI script…
<VirtualHost *:80>
  ServerName www.sprocketsrule.com
  DocumentRoot "/var/webapps/sprocketsrule/public"

  <Directory "/var/webapps/sprocketsrule/public">
    Options +ExecCGI +FollowSymLinks
                                                       Provided in the ext/
    AddHandler cgi-script .cgi                        directory of Sprockets
    RewriteEngine on
    RewriteCond /sprockets.js !-f
    RewriteRule ^sprockets.js /nph-sprockets.cgi [P,L]
    SetEnv sprockets_generate_output_file true
  </Directory>
</VirtualHost>




<script type="text/javascript" src="/sprockets.js"></script>
As a CGI script…
<VirtualHost *:80>




                                 T
  ServerName www.sprocketsrule.com




                               A
  DocumentRoot "/var/webapps/sprocketsrule/public"




                           N E
  <Directory "/var/webapps/sprocketsrule/public">
    Options +ExecCGI +FollowSymLinks
                                                       Provided in the ext/
    AddHandler cgi-script .cgi                        directory of Sprockets
    RewriteEngine on
    RewriteCond /sprockets.js !-f
    RewriteRule ^sprockets.js /nph-sprockets.cgi [P,L]
    SetEnv sprockets_generate_output_file true
  </Directory>
</VirtualHost>




<script type="text/javascript" src="/sprockets.js"></script>
…or use Rails!
…or use Rails!

$ script/plugin install git://github.com/sstephenson/sprockets-rails.git
…or use Rails!

$ script/plugin install git://github.com/sstephenson/sprockets-rails.git




ActionController::Routing::Routes.draw do |map|
  SprocketsApplication.routes(map)
  # ...
end
…or use Rails!

$ script/plugin install git://github.com/sstephenson/sprockets-rails.git




ActionController::Routing::Routes.draw do |map|
  SprocketsApplication.routes(map)
  # ...
end




<%= sprockets_include_tag %>
…or use Rails!



                                                  O M E
                         S
$ script/plugin install git://github.com/sstephenson/sprockets-rails.git




            A        W E
ActionController::Routing::Routes.draw do |map|
  SprocketsApplication.routes(map)
  # ...
end




<%= sprockets_include_tag %>
Hey, like to squeeze?
Hey, like to squeeze?


  Just because it’s one big file
doesn’t mean it’s one small file

     (that didn’t come out right)
YUI Compressor
YUI Compressor

• Arguably the best source shrinker out
  there
YUI Compressor

• Arguably the best source shrinker out
  there
• 100% safe yet full of optimizations
YUI Compressor

• Arguably the best source shrinker out
  there
• 100% safe yet full of optimizations
• Better than JSMin, ShrinkSafe, Packer…
YUI Compressor

• Arguably the best source shrinker out
  there
• 100% safe yet full of optimizations
• Better than JSMin, ShrinkSafe, Packer…
• Does not obfuscate (which is good)
YUI Compressor

• Arguably the best source shrinker out
  there
• 100% safe yet full of optimizations
• Better than JSMin, ShrinkSafe, Packer…
• Does not obfuscate (which is good)
• Distributed as a JAR file
The gem wrapper
The gem wrapper
$ sudo gem install --remote yui-compressor
The gem wrapper
$ sudo gem install --remote yui-compressor




compressor = YUI::JavaScriptCompressor.new(:munge => true)
compressor.compress('(function () { var foo = {}; foo["bar"] = "baz"; })()')
# => '(function(){var a={};a.bar="baz"})();'
The gem wrapper
$ sudo gem install --remote yui-compressor




compressor = YUI::JavaScriptCompressor.new(:munge => true)
compressor.compress('(function () { var foo = {}; foo["bar"] = "baz"; })()')
# => '(function(){var a={};a.bar="baz"})();'




YUI::JavaScriptCompressor.new(
  :java     => "/usr/bin/java",
  :jar_file => "/path/to/my/yuicompressor-2.4.2.jar"
)




      Full compressor support: CSS too, options aplenty…
A match made in heaven
# config/sprockets.yml

:asset_root: public
:load_path:
  - app/javascripts
  - vendor/sprockets/*/src
  - vendor/plugins/*/javascripts
:source_files:
  - app/javascripts/application.js
  - app/javascripts/**/*.js
:compress:
  :munge: true




        Warning: not in master gems yet. See my forks.
          (incidentally, in production use at http://letsfreckle.com)
So what’s left?
So what’s left?


• Tweak your assets HTTP server: GZip and
  cache the heck on the client side
So what’s left?


• Tweak your assets HTTP server: GZip and
  cache the heck on the client side
• If necessary, offload mainstream libs serving
  to Google
Apache config you’ll love
LoadModule deflate_module /usr/lib/apache2/modules/mod_deflate.so
LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so
LoadModule expires_module /usr/lib/apache2/modules/mod_expires.so

AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml
 ↪application/xhtml+xml text/javascript text/css application/x-javascript

ExpiresActive   On
ExpiresByType   image/gif "access plus 5 years"
ExpiresByType   image/png "access plus 5 years"
ExpiresByType   image/jpeg "access plus 5 years"
ExpiresByType   text/javascript "access plus 5 years"
ExpiresByType   application/x-javascript "access plus 5 years"
ExpiresByType   text/css "access plus 5 years"

Header unset ETag
FileETag None
Header add Cache-Control "public"



                http://javascriptrocks.com/performance/
Numbers!

                                 No opti.                  All opti.

       Bytes                     292.520                   30.919

   HTTP requests                  3 / 38*                     1

Load time (unprimed)          1900+456ms              400+43ms

 Load time (primed)            1900+76ms               1+41ms

         * monolithic vendor scripts / structured source
Numbers!

                                 No opti.                  All opti.

       Bytes                     292.520                   30.919

   HTTP requests                  3 / 38*                     1

Load time (unprimed)          1900+456ms              400+43ms

 Load time (primed)            1900+76ms               1+41ms

         * monolithic vendor scripts / structured source
Numbers!

                                 No opti.                  All opti.

       Bytes                     292.520                   30.919

   HTTP requests                  3 / 38*                     1

Load time (unprimed)          1900+456ms              400+43ms

 Load time (primed)            1900+76ms               1+41ms

         * monolithic vendor scripts / structured source
Numbers!

                                 No opti.                  All opti.

       Bytes                     292.520                   30.919

   HTTP requests                  3 / 38*                     1

Load time (unprimed)          1900+456ms              400+43ms

 Load time (primed)            1900+76ms               1+41ms

         * monolithic vendor scripts / structured source
Numbers!

                                 No opti.                  All opti.

       Bytes                     292.520                   30.919

   HTTP requests                  3 / 38*                     1

Load time (unprimed)          1900+456ms              400+43ms

 Load time (primed)            1900+76ms               1+41ms

         * monolithic vendor scripts / structured source
Numbers!


                                    V
                                 No opti.                  All opti.

       Bytes



          Y M
   HTTP requests

Load time (unprimed)
                                  M
                                 292.520

                                  3 / 38*

                              1900+456ms
                                                           30.919



                                                      400+43ms
                                                              1



 Load time (primed)            1900+76ms               1+41ms

         * monolithic vendor scripts / structured source
Google Ajax Libraries API
Google Ajax Libraries API

• Google hosts most recent versions of
  Prototype, jQuery, script.aculo.us,
  MooTools, Dojo, Ext Core,YUI…
Google Ajax Libraries API

• Google hosts most recent versions of
  Prototype, jQuery, script.aculo.us,
  MooTools, Dojo, Ext Core,YUI…
• Top-notch serving (e.g. cache-related
  headers + GZipping) + CDN
Google Ajax Libraries API

• Google hosts most recent versions of
  Prototype, jQuery, script.aculo.us,
  MooTools, Dojo, Ext Core,YUI…
• Top-notch serving (e.g. cache-related
  headers + GZipping) + CDN
• Bonus: if another site loaded it already, your
  user doesn’t have to load it for your site!
Thank you, Sam.
Thank you, Sam.
•   Sprockets, Sprockets-Rails and
    YUI::Compressor are open-
    source stuff by Sam
    Stephenson, creator of
    Prototype.
Thank you, Sam.
•   Sprockets, Sprockets-Rails and
    YUI::Compressor are open-
    source stuff by Sam
    Stephenson, creator of
    Prototype.

•   http://github.com/sstephenson
Thank you, Sam.
•   Sprockets, Sprockets-Rails and
    YUI::Compressor are open-
    source stuff by Sam
    Stephenson, creator of
    Prototype.

•   http://github.com/sstephenson

•   http://github.com/tdd
Sprockets
Thank you!
   Any questions?



 Christophe Porteneuve
  tdd@tddsworld.com
     JSConf.eu 2009

More Related Content

Sprockets

  • 1. Sprockets You’ve got tons of JavaScript. Time to do something about it. Christophe Porteneuve JSConf.eu 2009
  • 2. Hi, I’m Christophe • I’m 32 and I live in Paris, France • I use Rails all day at work • I’m a Prototype Core member • I wrote Prototype and script.aculo.us (“The Bungee Book”) • I’m glad to be here!
  • 4. The problem • JavaScript is the next big language…
  • 5. The problem • JavaScript is the next big language… • It’s already getting big, codewise!
  • 6. The problem • JavaScript is the next big language… • It’s already getting big, codewise! • Many apps have countless JS files
  • 7. The problem • JavaScript is the next big language… • It’s already getting big, codewise! • Many apps have countless JS files • Loading → lots of requests → latence
  • 8. The problem • JavaScript is the next big language… • It’s already getting big, codewise! • Many apps have countless JS files • Loading → lots of requests → latence • Or you could maintain one big file…
  • 9. The problem • JavaScript is the next big language… • It’s already getting big, codewise! • Many apps have countless JS files • Loading → lots of requests → latence • Or you could maintain one big file… • …which sucks
  • 11. The solution • You want to split your JS code in neat files and folders!
  • 12. The solution • You want to split your JS code in neat files and folders! • You want some structure, dammit!
  • 13. The solution • You want to split your JS code in neat files and folders! • You want some structure, dammit! • But you want to serve just one file!
  • 14. The solution • You want to split your JS code in neat files and folders! • You want some structure, dammit! • But you want to serve just one file! • Enter Sprockets
  • 15. So many cool things…
  • 16. So many cool things… • Use require directives and load paths to structure your source
  • 17. So many cool things… • Use require directives and load paths to structure your source • Preprocess constants!
  • 18. So many cool things… • Use require directives and load paths to structure your source • Preprocess constants! • Create “JS plugins,” complete with related CSS/image assets, bundle them and distribute them easily
  • 20. Getting organized … //= require "lang" //= require "ajax" //= require "dom"
  • 21. Getting organized //= require "dom/dom" //= require "dom/selector" //= require "dom/form" //= require "dom/event" Element.addMethods(); … //= require "lang" //= require "ajax" //= require "dom"
  • 22. Getting organized //= require "ajax/ajax" //= require "ajax/responders" //= require "ajax/base" //= require "ajax/request" //= require "ajax/response" //= require "ajax/updater" //= require "ajax/periodical_updater" //= require "dom/dom" //= require "dom/selector" //= require "dom/form" //= require "dom/event" Element.addMethods(); … //= require "lang" //= require "ajax" //= require "dom"
  • 23. The load path Sprockets has a load path, much like C’s or Ruby’s
  • 24. The load path Sprockets has a load path, much like C’s or Ruby’s Using the load path: //= require <coolobj> //= require <coollib/coolobj>
  • 25. The load path Sprockets has a load path, much like C’s or Ruby’s Using the load path: //= require <coolobj> //= require <coollib/coolobj> Using paths relative to the current file: //= require "coolobj" //= require "subdir/coolobj"
  • 26. Constants FTW! Put a constants.yml file somewhere in your load path • It’s a YAML file • Heard of YAML, right? • Super simple yet powerful
  • 29. Constants for you PROTOTYPE_VERSION: 1.6.1_rc3
  • 30. Constants for you PROTOTYPE_VERSION: 1.6.1_rc3 var Prototype = { Version: '<%= PROTOTYPE_VERSION %>', Browser: (function(){ …
  • 31. Bundling assets //= require "color" //= provide "../assets" Because you require <color_picker>, Sprockets can copy the assets to your asset root (somewhere inside your document root)
  • 32. I can haz? • It’s a Ruby gem • You don’t need to know Ruby though • You do need Ruby and Rubygems installed
  • 33. I can haz? • It’s a Ruby gem • You don’t need to know Ruby though • You do need Ruby and Rubygems installed $ sudo gem install --remote sprockets
  • 34. As a command-line tool… $ sprocketize Usage: sprocketize [options] filename [filename ...] -C, --directory=DIRECTORY Change to DIRECTORY before doing anything -I, --include-dir=DIRECTORY Adds the directory to the Sprockets load path -a, --asset-root=DIRECTORY Copy provided assets into DIRECTORY … -h, --help Shows this help message -v, --version Shows version
  • 35. As a command-line tool… $ sprocketize Usage: sprocketize [options] filename [filename ...] -C, --directory=DIRECTORY Change to DIRECTORY before doing anything -I, --include-dir=DIRECTORY Adds the directory to the Sprockets load path -a, --asset-root=DIRECTORY Copy provided assets into DIRECTORY … -h, --help Shows this help message -v, --version Shows version $ sprocketize -I src -a dist src/application.js > dist/javascripts/application.js
  • 37. Within Ruby code… require 'rubygems' require 'sprockets' secretary = Sprockets::Secretary.new( :asset_root => "public", :load_path => ["vendor/sprockets/*/src", "vendor/plugins/*/javascripts"], :source_files => ["app/javascripts/application.js", "app/javascripts/**/*.js"] ) concatenation = secretary.concatenation concatenation.save_to("public/sprockets.js") secretary.install_assets
  • 38. As a CGI script… Say you have this tree
  • 39. As a CGI script… Say you have this tree :load_path: - javascripts - vendor/sprockets/*/src :source_files: - javascripts/mysite.js - javascripts/*.js :output_file: public/sprockets.js So you write this sprockets.yml
  • 40. As a CGI script… <VirtualHost *:80> ServerName www.sprocketsrule.com DocumentRoot "/var/webapps/sprocketsrule/public" <Directory "/var/webapps/sprocketsrule/public"> Options +ExecCGI +FollowSymLinks AddHandler cgi-script .cgi RewriteEngine on RewriteCond /sprockets.js !-f RewriteRule ^sprockets.js /nph-sprockets.cgi [P,L] SetEnv sprockets_generate_output_file true </Directory> </VirtualHost> <script type="text/javascript" src="/sprockets.js"></script>
  • 41. As a CGI script… <VirtualHost *:80> ServerName www.sprocketsrule.com DocumentRoot "/var/webapps/sprocketsrule/public" <Directory "/var/webapps/sprocketsrule/public"> Options +ExecCGI +FollowSymLinks Provided in the ext/ AddHandler cgi-script .cgi directory of Sprockets RewriteEngine on RewriteCond /sprockets.js !-f RewriteRule ^sprockets.js /nph-sprockets.cgi [P,L] SetEnv sprockets_generate_output_file true </Directory> </VirtualHost> <script type="text/javascript" src="/sprockets.js"></script>
  • 42. As a CGI script… <VirtualHost *:80> T ServerName www.sprocketsrule.com A DocumentRoot "/var/webapps/sprocketsrule/public" N E <Directory "/var/webapps/sprocketsrule/public"> Options +ExecCGI +FollowSymLinks Provided in the ext/ AddHandler cgi-script .cgi directory of Sprockets RewriteEngine on RewriteCond /sprockets.js !-f RewriteRule ^sprockets.js /nph-sprockets.cgi [P,L] SetEnv sprockets_generate_output_file true </Directory> </VirtualHost> <script type="text/javascript" src="/sprockets.js"></script>
  • 44. …or use Rails! $ script/plugin install git://github.com/sstephenson/sprockets-rails.git
  • 45. …or use Rails! $ script/plugin install git://github.com/sstephenson/sprockets-rails.git ActionController::Routing::Routes.draw do |map| SprocketsApplication.routes(map) # ... end
  • 46. …or use Rails! $ script/plugin install git://github.com/sstephenson/sprockets-rails.git ActionController::Routing::Routes.draw do |map| SprocketsApplication.routes(map) # ... end <%= sprockets_include_tag %>
  • 47. …or use Rails! O M E S $ script/plugin install git://github.com/sstephenson/sprockets-rails.git A W E ActionController::Routing::Routes.draw do |map| SprocketsApplication.routes(map) # ... end <%= sprockets_include_tag %>
  • 48. Hey, like to squeeze?
  • 49. Hey, like to squeeze? Just because it’s one big file doesn’t mean it’s one small file (that didn’t come out right)
  • 51. YUI Compressor • Arguably the best source shrinker out there
  • 52. YUI Compressor • Arguably the best source shrinker out there • 100% safe yet full of optimizations
  • 53. YUI Compressor • Arguably the best source shrinker out there • 100% safe yet full of optimizations • Better than JSMin, ShrinkSafe, Packer…
  • 54. YUI Compressor • Arguably the best source shrinker out there • 100% safe yet full of optimizations • Better than JSMin, ShrinkSafe, Packer… • Does not obfuscate (which is good)
  • 55. YUI Compressor • Arguably the best source shrinker out there • 100% safe yet full of optimizations • Better than JSMin, ShrinkSafe, Packer… • Does not obfuscate (which is good) • Distributed as a JAR file
  • 57. The gem wrapper $ sudo gem install --remote yui-compressor
  • 58. The gem wrapper $ sudo gem install --remote yui-compressor compressor = YUI::JavaScriptCompressor.new(:munge => true) compressor.compress('(function () { var foo = {}; foo["bar"] = "baz"; })()') # => '(function(){var a={};a.bar="baz"})();'
  • 59. The gem wrapper $ sudo gem install --remote yui-compressor compressor = YUI::JavaScriptCompressor.new(:munge => true) compressor.compress('(function () { var foo = {}; foo["bar"] = "baz"; })()') # => '(function(){var a={};a.bar="baz"})();' YUI::JavaScriptCompressor.new( :java => "/usr/bin/java", :jar_file => "/path/to/my/yuicompressor-2.4.2.jar" ) Full compressor support: CSS too, options aplenty…
  • 60. A match made in heaven # config/sprockets.yml :asset_root: public :load_path: - app/javascripts - vendor/sprockets/*/src - vendor/plugins/*/javascripts :source_files: - app/javascripts/application.js - app/javascripts/**/*.js :compress: :munge: true Warning: not in master gems yet. See my forks. (incidentally, in production use at http://letsfreckle.com)
  • 62. So what’s left? • Tweak your assets HTTP server: GZip and cache the heck on the client side
  • 63. So what’s left? • Tweak your assets HTTP server: GZip and cache the heck on the client side • If necessary, offload mainstream libs serving to Google
  • 64. Apache config you’ll love LoadModule deflate_module /usr/lib/apache2/modules/mod_deflate.so LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so LoadModule expires_module /usr/lib/apache2/modules/mod_expires.so AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml ↪application/xhtml+xml text/javascript text/css application/x-javascript ExpiresActive On ExpiresByType image/gif "access plus 5 years" ExpiresByType image/png "access plus 5 years" ExpiresByType image/jpeg "access plus 5 years" ExpiresByType text/javascript "access plus 5 years" ExpiresByType application/x-javascript "access plus 5 years" ExpiresByType text/css "access plus 5 years" Header unset ETag FileETag None Header add Cache-Control "public" http://javascriptrocks.com/performance/
  • 65. Numbers! No opti. All opti. Bytes 292.520 30.919 HTTP requests 3 / 38* 1 Load time (unprimed) 1900+456ms 400+43ms Load time (primed) 1900+76ms 1+41ms * monolithic vendor scripts / structured source
  • 66. Numbers! No opti. All opti. Bytes 292.520 30.919 HTTP requests 3 / 38* 1 Load time (unprimed) 1900+456ms 400+43ms Load time (primed) 1900+76ms 1+41ms * monolithic vendor scripts / structured source
  • 67. Numbers! No opti. All opti. Bytes 292.520 30.919 HTTP requests 3 / 38* 1 Load time (unprimed) 1900+456ms 400+43ms Load time (primed) 1900+76ms 1+41ms * monolithic vendor scripts / structured source
  • 68. Numbers! No opti. All opti. Bytes 292.520 30.919 HTTP requests 3 / 38* 1 Load time (unprimed) 1900+456ms 400+43ms Load time (primed) 1900+76ms 1+41ms * monolithic vendor scripts / structured source
  • 69. Numbers! No opti. All opti. Bytes 292.520 30.919 HTTP requests 3 / 38* 1 Load time (unprimed) 1900+456ms 400+43ms Load time (primed) 1900+76ms 1+41ms * monolithic vendor scripts / structured source
  • 70. Numbers! V No opti. All opti. Bytes Y M HTTP requests Load time (unprimed) M 292.520 3 / 38* 1900+456ms 30.919 400+43ms 1 Load time (primed) 1900+76ms 1+41ms * monolithic vendor scripts / structured source
  • 72. Google Ajax Libraries API • Google hosts most recent versions of Prototype, jQuery, script.aculo.us, MooTools, Dojo, Ext Core,YUI…
  • 73. Google Ajax Libraries API • Google hosts most recent versions of Prototype, jQuery, script.aculo.us, MooTools, Dojo, Ext Core,YUI… • Top-notch serving (e.g. cache-related headers + GZipping) + CDN
  • 74. Google Ajax Libraries API • Google hosts most recent versions of Prototype, jQuery, script.aculo.us, MooTools, Dojo, Ext Core,YUI… • Top-notch serving (e.g. cache-related headers + GZipping) + CDN • Bonus: if another site loaded it already, your user doesn’t have to load it for your site!
  • 76. Thank you, Sam. • Sprockets, Sprockets-Rails and YUI::Compressor are open- source stuff by Sam Stephenson, creator of Prototype.
  • 77. Thank you, Sam. • Sprockets, Sprockets-Rails and YUI::Compressor are open- source stuff by Sam Stephenson, creator of Prototype. • http://github.com/sstephenson
  • 78. Thank you, Sam. • Sprockets, Sprockets-Rails and YUI::Compressor are open- source stuff by Sam Stephenson, creator of Prototype. • http://github.com/sstephenson • http://github.com/tdd
  • 80. Thank you! Any questions? Christophe Porteneuve tdd@tddsworld.com JSConf.eu 2009