WCEU: Seven Times Faster : A Study in frontend Optimization

WCEU: Seven Times Faster : A Study in frontend Optimization

The average web page takes fifteen seconds to load, this can lower the PageSpeed score to the low 30s. Working together web designers and devs can make sites readable in two seconds, working towards a web seven times faster.

Find out how to get a PageSpeed score in the 90s. What are the rules you have to follow, what are those you have to break?

1dd9fded718f9b344d48f37f9bfcb159?s=128

Peter Wilson

June 24, 2016
Tweet

Transcript

  1. Wed 29 Oct 1969 ~ ucla$ ░

  2. Wed 29 Oct 1969 ~ ucla$ ░

  3. Wed 29 Oct 1969 ~ ucla$ lo ░ gin

  4. Wed 29 Oct 1969 ~ ucla$ lo ░ ░

  5. Seven times faster: 
 a study in front-end optimisation Peter

    Wilson • peterwilson.cc • @pwcc
  6. None
  7. WordPress is slow

  8. Front-end code is slow

  9. Bytes on the page

  10. Total page size (MB) Nov 2011 - March 2016 0.5

    1.0 1.5 2.0 2.5 1 Nov '11 15 May '12 1 Dec '12 15 Jun '13 1 Jan '14 15 Jul '14 1 Feb '15 15 Aug '15 1 Mar '16 httparchive.org/trends.php, March 2016
  11. Assets per page Nov 2011 - March 2016 20 40

    60 80 100 120 1 Nov '11 15 May '12 1 Dec '12 15 Jun '13 1 Jan '14 15 Jul '14 1 Feb '15 15 Aug '15 1 Mar '16 httparchive.org/trends.php, March 2016
  12. Webfonts Multiple of Nov 2011 (bytes) 2 4 6 8

    10 12 14 16 18 1 Nov '11 15 May '12 1 Dec '12 15 Jun '13 1 Jan '14 15 Jul '14 1 Feb '15 15 Aug '15 1 Mar '16 httparchive.org/trends.php, March 2016
  13. Load time httparchive.org/trends.php, March 2016

  14. Load time Start render: 4.2 seconds

  15. Load time Visually complete: 12.7 seconds

  16. Load time Document complete: 15.23 sec

  17. Two seconds

  18. Walmart conversion rate slideshare.net/devonauerswald/walmart-pagespeedslide 0 - 1 1 - 2

    2 - 3 3 - 4 4 - 5 5 - 6 6 - 7 7 - 8 8 - 9 9 - 10 10 - 11 11 - 12 12 - 13 13 - 14 14 - 15 15+
  19. The average site kills conversions.

  20. Measure a starting point

  21. None
  22. WebPageTest - webpagetest.org

  23. Key metrics Document Complete Fully Loaded Load Time First Byte

    Start Render Speed Index DOM Elements Time Requests Bytes In Time Requests Bytes In 3.770s 0.771s 1.789s 1834 397 3.770s 27 635 KB 4.072s 33 661 KB WebPageTest - webpagetest.org
  24. Timeline view

  25. Comparison timelines Additional blocking request in HTML Header Timed using

    WebPageTest - pwcc.cc/wceu/blocking 0.5s 1.0s 1.5s 2.0s 0% 0% 0% 100% 0% 86% 100% Blocked Unblocked
  26. 53 / 100 Our PageSpeed score is you won’t believe

    how
 much it’s costing
  27. What will get my visitors reading quickest? “ ”

  28. Doing it wrong

  29. JavaScript in the footer

  30. All visitors have JavaScript disabled while it downloads. – Every

    progressive enhancement advocate ever “ ”
  31. wp_enqueue_script( 'pwcc-scripts', // handle '/functions.js', // source null, // no

    dependancies '20160624-26', // version true // load in footer ); JavaScript, the WordPress way
  32. wp_enqueue_script( 'pwcc-scripts', // handle '/functions.js', // source null, // no

    dependancies '20160624-26', // version true // load in footer ); true // load in footer JavaScript, the WordPress way
  33. wp_enqueue_script( 'pwcc-scripts', // handle '/functions.js', // source array( 'jquery' ),

    // jQuery loads automatically '20160624-26', // version true // load in footer ); jQuery, the WordPress way
  34. wp_enqueue_script( 'pwcc-scripts', // handle '/functions.js', // source array( 'jquery' ),

    // jQuery loads automatically '20160624-26', // version true // load in footer ); array( 'jquery' ), // jQuery loads automatically jQuery, the WordPress way
  35. <html> <head> <script src='jquery.js'></script><!--32kB--> <script src='jquery-migrate.js'></script><!--4.4kB--> </head> <body> <!-- Site

    content. --> <script src='/functions.js'></script> jQuery, doing_it_wrong()
  36. <html> <head> <script src='jquery.js'></script><!--32kB--> <script src='jquery-migrate.js'></script><!--4.4kB--> </head> <body> <!-- Site

    content. --> <script src='/functions.js'></script> </body> </html> jQuery, doing_it_wrong()
  37. The WordPress way blocks rendering Daniel Zedda (CC) - flic.kr/p/a6wwAh

  38. function pwcc_jquery_to_footer() { if ( is_admin() ) return; wp_script_add_data( 'jquery',

    'group', 1 ); wp_script_add_data( 'jquery-core', 'group', 1 ); wp_script_add_data( 'jquery-migrate', 'group', 1 ); } add_action( 'wp', 'pwcc_jquery_to_footer' ); jQuery, doing_it_wrong()
  39. function pwcc_jquery_to_footer() { if ( is_admin() ) return; wp_script_add_data( 'jquery',

    'group', 1 ); wp_script_add_data( 'jquery-core', 'group', 1 ); wp_script_add_data( 'jquery-migrate', 'group', 1 ); } add_action( 'wp', 'pwcc_jquery_to_footer' ); wp_script_add_data( 'jquery', 'group', 1 ); wp_script_add_data( 'jquery-core', 'group', 1 ); wp_script_add_data( 'jquery-migrate', 'group', 1 ); jQuery, doing_it_wrong()
  40. function pwcc_jquery_to_footer() { if ( is_admin() ) return; wp_script_add_data( 'jquery',

    'group', 1 ); wp_script_add_data( 'jquery-core', 'group', 1 ); wp_script_add_data( 'jquery-migrate', 'group', 1 ); } add_action( 'wp', 'pwcc_jquery_to_footer' ); wp_script_add_data( 'jquery', 'group', 1 ); wp_script_add_data( 'jquery-core', 'group', 1 ); wp_script_add_data( 'jquery-migrate', 'group', 1 ); jQuery, doing_it_wrong()
  41. <html> <head> <script src='jquery.js'></script><!--32kB--> <script src='jquery-migrate.js'></script><!--4.4kB--> </head> <body> <!-- Site

    content. --> <script src='/functions.js'></script> jQuery, the WordPress way
  42. <html> <head> <!-- HTML Header. --> </head> <body> <!-- Site

    content. --> <script src='jquery.js'></script><!--32kB--> <script src='jquery-migrate.js'></script><!--4.4kB--> <script src='/functions.js'></script> </body> jQuery, doing_it_wrong()
  43. <html> <head> <!-- HTML Header. --> </head> <body> <!-- Site

    content. --> <script src='jquery.js'></script><!--32kB--> <script src='jquery-migrate.js'></script><!--4.4kB--> <script src='/functions.js'></script> </body> </html> jQuery, doing_it_wrong() pwcc.cc/wceu/jqueryfooter
  44. Asynchronous JavaScript

  45. Asynchronous JavaScript <script type='text/javascript' src='/path/file.js' async></script>

  46. Asynchronous JavaScript <script type='text/javascript' src='/path/file.js' async></script> async

  47. function pwcc_async_js( $tag, $handle ) { switch ( $handle )

    { case 'pwcc-scripts' : $tag = str_replace( '></script', ' async></script', $tag ); } return $tag; } Asynchronous JavaScript
  48. function pwcc_async_js( $tag, $handle ) { switch ( $handle )

    { case 'pwcc-scripts' : // Falls through case 'picturefill' : $tag = str_replace( '></script', ' async></script', $tag ); } return $tag; } Asynchronous JavaScript
  49. function pwcc_async_js( $tag, $handle ) { switch ( $handle )

    { case 'pwcc-scripts' : // Falls through case 'picturefill' : $tag = str_replace( '></script', ' async></script', $tag ); } return $tag; } Asynchronous JavaScript
  50. switch ( $handle ) { case 'pwcc-scripts' : // Falls

    through case 'picturefill' : $tag = str_replace( '></script', ' async></script', $tag ); } return $tag; } add_filter( 'script_loader_tag', 'pwcc_async_js', 10, 2 ); Asynchronous JavaScript
  51. function pw_async_up() { wp_script_add_data( 'picturefill', 'group', 0 ); wp_script_add_data( 'pwcc-scripts',

    'group', 0 ); } add_action( 'wp_enqueue_scripts', 'pw_async_up' , 99 ); Asynchronous JS in the header
  52. function pw_async_up() { wp_script_add_data( 'picturefill', 'group', 0 ); wp_script_add_data( 'pwcc-scripts',

    'group', 0 ); } add_action( 'wp_enqueue_scripts', 'pw_async_up' , 99 ); Asynchronous JS in the header pwcc.cc/wceu/asyncjs
  53. Browsers initiate requests The blocking nature of HTTP 1

  54. Blockers HTML

  55. Blockers HTML CSS

  56. Blockers HTML CSS

  57. Blockers HTML CSS IMG IMG IMG FONTS

  58. Blockers HTML CSS IMG IMG IMG JS FONTS

  59. Blockers HTML CSS IMG IMG IMG JS IFRAME FONTS

  60. Waterfall WebPageTest - webpagetest.org

  61. Waterfall WebPageTest - webpagetest.org

  62. Waterfall HTML CSS IMG IMG IMG JS IFRAME FONTS

  63. Waterfall HTML CSS IMG IMG IMG JS IFRAME FONTS

  64. HTTP/2 An aside

  65. Everything you know about performance is now wrong and former

    best practices are now an anti-pattern and considered harmful.
  66. These titles are considered harmful

  67. Sites using HTTP/2 w3techs.com, March 2016

  68. caniuse.com/http2, March 2016

  69. caniuse.com/http2, March 2016

  70. Critical Path CSS

  71. w3.org/TR/preload/

  72. HTTP/2, without critical path CSS HTML CSS

  73. HTTP/1, with critical path CSS HTML CSS

  74. <html> <head> <style>html{font-family:sans-serif;-ms-text-size-adjust: 100%;-webkit-text-size-adjust:100%}body{margin:0}article, aside,details,figcaption,figure,footer,header,hgroup,main, nav,section,summary{display:block}audio,canvas,progress, video{display:inline-block;vertical-align:baseline} audio:not([controls]){display:none;height:0}[hidden], template{display:none}a{background:transparent}a:active, a:hover{outline:0}abbr[title]{border-bottom:1px

    dotted} b,strong{font-weight:bold}dfn{font-style:italic}h1{font-
  75. HTTP/1, with critical path CSS HTML CSS

  76. HTTP/1, without critical path CSS HTML CSS

  77. CSS, the WordPress way wp_enqueue_style( 'pwcc-style', // handle get_stylesheet_uri(), //

    source array(), // no dependancies '20160624-26', // version 'all' // media );
  78. Preloading CSS

  79. Preloading CSS

  80. Preloading CSS Link: </style.css>; rel=preload; as=style; nopush

  81. Preloading CSS Link: </style.css>; rel=preload; as=style; nopush

  82. Preloading CSS pwcc_preload_style( 'pwcc-style' ); // push pwcc_preload_style( 'pwcc-style', false

    ); // no push
  83. Server push pwcc_preload_style( 'pwcc-style' );

  84. Server push if ( is_cached( 'pwcc-style' ) ) { pwcc_preload_style(

    'pwcc-style' ); } else /* file not cached */ { pwcc_preload_style( 'pwcc-style', false ); }
  85. $version = '20160624-26'; setcookie( 'pwcc-style', $version, 0, '/' ); Server

    push
  86. is_cached() function is_cached( $handle, $version ) { if ( $version

    === $_COOKIE[ $handle ] ) { return true; } else { return false; } }
  87. <html> <head> <style>html{font-family:sans-serif;-ms-text-size-adjust: 100%;-webkit-text-size-adjust:100%}body{margin:0}article, aside,details,figcaption,figure,footer,header,hgroup,main, nav,section,summary{display:block}audio,canvas,progress, video{display:inline-block;vertical-align:baseline} audio:not([controls]){display:none;height:0}[hidden], template{display:none}a{background:transparent}a:active, a:hover{outline:0}abbr[title]{border-bottom:1px

    dotted} b,strong{font-weight:bold}dfn{font-style:italic}h1{font-
  88. None
  89. pwcc.cc/wceu/loadcss

  90. Register loadCSS wp_register_script( 'pwcc-load-css', // handle '/loadcss.js', // file array(),

    // dependencies "1.2.0", // version true // load in footer );
  91. <style type='text/css'>/* Critical CSS */</style> <link rel='preload' href='/style.css' as='style' onload='this.rel="stylesheet"'>

    <noscript> <link rel='stylesheet' href='/style.css' /> </noscript> HTML: uncached HTTP/1
  92. if ( ! is_cached( 'pwcc-style' ) && ! is_http2() )

    { print_style_inline( 'pwcc-style' ); wp_enqueue_script( 'pwcc-load-css' ); } Inline CSS
  93. if ( ! is_cached( 'pwcc-style' ) && ! is_http2() )

    { print_style_inline( 'pwcc-style' ); wp_enqueue_script( 'pwcc-load-css' ); } Inline CSS pwcc.cc/wceu/rapidcss
  94. <html> <head> <style>html{font-family:sans-serif;-ms-text-size-adjust: 100%;-webkit-text-size-adjust:100%}body{margin:0}article, aside,details,figcaption,figure,footer,header,hgroup,main, nav,section,summary{display:block}audio,canvas,progress, video{display:inline-block;vertical-align:baseline} audio:not([controls]){display:none;height:0}[hidden], template{display:none}a{background:transparent}a:active, a:hover{outline:0}abbr[title]{border-bottom:1px

    dotted} b,strong{font-weight:bold}dfn{font-style:italic}h1{font-
  95. <link rel="stylesheet" href="/style.css" /> Cached Stylesheet

  96. <link rel='shortcut icon' href='/favicon.ico'> <link rel='apple-touch-icon' sizes='57x57' href='/….png'> <link rel='apple-touch-icon'

    sizes='114x114' href='/….png'> <link rel='apple-touch-icon' sizes='72x72' href='/….png'> <link rel='apple-touch-icon' sizes='144x144' href='/….png'> <link rel='apple-touch-icon' sizes='60x60' href='/….png'> <link rel='apple-touch-icon' sizes='120x120' href='/….png'> <link rel='apple-touch-icon' sizes='76x76' href='/….png'> <link rel='apple-touch-icon' sizes='152x152' href='/….png'> <link rel='icon' type='image/png' href='/….png'> <link rel='icon' type='image/png' href='/….png' sizes='160x160'> <link rel='icon' type='image/png' href='/….png' sizes='96x96'> <link rel='icon' type='image/png' href='/….png' sizes='16x16'> <link rel='icon' type='image/png' href='/….png' sizes='32x32'> <meta name='msapplication-TileColor' content='#006ef6'> <meta name='msapplication-TileImage' content='/….png'> <meta name='msapplication-config' content='/browserconfig.xml'>
  97. Everything you know about performance is now wrong and former

    best practices are now an anti-pattern and considered harmful.
  98. Everything you know about performance is now twice as complicated.

  99. Thank you Peter Wilson • peterwilson.cc • @pwcc