Wed 29 Oct 1969 ~ ucla$ ░

Wed 29 Oct 1969 ~ ucla$ ░

Wed 29 Oct 1969 ~ ucla$ l o

░
								
gin

Wed 29 Oct 1969 ~ ucla$ l o

░ ░

Seven times faster: 
 a study in front-end optimisation Peter Wilson • peterwilson.cc • @pwcc

WordPress is slow

Front-end code is slow

Bytes on the page

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

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

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

Load time httparchive.org/trends.php , March 2016

Load time Start render: 4.2 seconds

Load time Visually complete: 12.7 seconds

Load time Document complete: 15.23 sec

Two seconds

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+

The average site kills conversions.

Measure a starting point

WebPageTest - webpagetest.org

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

Timeline view

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

53 / 100 Our PageSpeed score is you won’t believe how 
 much it’s costing

What will get my visitors reading quickest? “ ”

Doing it wrong

JavaScript in the footer

All visitors have JavaScript disabled while it downloads. – Every progressive enhancement advocate ever “ ”

wp_enqueue_script(

'pwcc-scripts' , // handle

'/functions.js' , // source

null , // no dependancies

'20160624-26' , // version

true

// load in footer ); JavaScript, the WordPress way

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

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

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

< 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

jQuery, doing_it_wrong()

< 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()

The WordPress way blocks rendering Daniel Zedda (CC) - flic.kr/p/a6wwAh

function

pwcc_jquery_to_footer () {

if ( is_admin() )

return ;

w p _ s c r i p t _ a d d _ d a t a ( 	

'jquery' , 'group' , 1 ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery-core' , 'group' , 1 ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery-migrate' , 'group' , 1 ); } add_action( 'wp' , 'pwcc_jquery_to_footer' ); jQuery, doing_it_wrong()

function

pwcc_jquery_to_footer () {

if ( is_admin() )

return ;

w p _ s c r i p t _ a d d _ d a t a ( 	

'jquery' , 'group' , 1 ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery-core' , 'group' , 1 ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery-migrate' , 'group' , 1 ); } add_action( 'wp' , 'pwcc_jquery_to_footer' ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery' , 'group' , 1 ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery-core' , 'group' , 1 ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery-migrate' , 'group' , 1 ); jQuery, doing_it_wrong()

function

pwcc_jquery_to_footer () {

if ( is_admin() )

return ;

w p _ s c r i p t _ a d d _ d a t a ( 	

'jquery' , 'group' , 1 ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery-core' , 'group' , 1 ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery-migrate' , 'group' , 1 ); } add_action( 'wp' , 'pwcc_jquery_to_footer' ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery' , 'group' , 1 ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery-core' , 'group' , 1 ); w p _ s c r i p t _ a d d _ d a t a ( 'jquery-migrate' , 'group' , 1 ); jQuery, doing_it_wrong()

< 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

jQuery, the WordPress way

< 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()

< 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

A s y n c h r o n o u s J a v a S c r i p t

Asynchronous JavaScript < script

type

'text/javascript'

src

'/path/file.js'

async

</ script

Asynchronous JavaScript < script

type

'text/javascript'

src

'/path/file.js'

async

</ script

async

function

pwcc_async_js ( $tag, $handle ) {

switch ( $handle ) {

case

'pwcc-scripts' :

		$tag	

=

str_replace ( '></script' , ' async></script' , $tag );

}

return $tag; }

Asynchronous JavaScript

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

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

function

pwcc_async_js ( $tag, $handle ) {

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

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

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

Browsers initiate requests The blocking nature of HTTP 1

Blockers HTML

Blockers HTML CSS

Blockers HTML CSS

Blockers HTML CSS IMG IMG IMG FONTS

Blockers HTML CSS IMG IMG IMG JS FONTS

Blockers HTML CSS IMG IMG IMG JS IFRAME FONTS

Waterfall WebPageTest - webpagetest.org

WebPageTest - webpagetest.org

Waterfall

Waterfall HTML CSS IMG IMG IMG JS IFRAME FONTS

Waterfall HTML CSS IMG IMG IMG JS IFRAME FONTS

HTTP/2 An aside

Everything you know about performance is now wrong and former best practices are now an anti-pattern and considered harmful.

These titles are considered harmful

Sites using HTTP/2 w3techs.com , March 2016

caniuse.com/http2 , March 2016

caniuse.com/http2 , March 2016

Critical Path CSS

w3.org/TR/preload/

HTTP/2, without critical path CSS HTML CSS

HTTP/1, with critical path CSS HTML CSS

< 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 : 1 px

dotted } b , strong { font-weight : bold } dfn { font-style : italic } h1 { font- size : 2 em ; margin : 0.67 em

0 } mark { background : #ff0 ; color : #000 }

HTTP/1, with critical path CSS HTML CSS

HTTP/1, without critical path CSS HTML CSS

CSS, the WordPress way wp_enqueue_style(

'pwcc-style' , // handle

	get_stylesheet_uri(),			

// source

array (), // no dependancies

'20160624-26' , // version

'all'

// media

);

Preloading CSS

Preloading CSS

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

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

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

Server push pwcc_preload_style ( 'pwcc-style' );

Server push if ( is_cached( 'pwcc-style' ) ) { pwcc_preload_style( 'pwcc-style' ); } else

/* file not cached */ {

	pwcc_preload_style(	

'pwcc-style' , false ); }

$version

'20160624-26' ; setcookie ( 'pwcc-style' , $version, 0 , '/' ); Server push

is_cached() function

is_cached ( $handle, $version ) {

if ( $version

$_COOKIE[	$handle	]	)	{	
			

return

true ;

	}	
	

else {

return

false ;

	}	

}

< 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 : 1 px

dotted } b , strong { font-weight : bold } dfn { font-style : italic } h1 { font- size : 2 em ; margin : 0.67 em

0 } mark { background : #ff0 ; color : #000 }

pwcc.cc/wceu/loadcss

Register loadCSS wp_register_script(

'pwcc-load-css' , // handle

'/loadcss.js' , // file

array (), // dependencies

"1.2.0" , // version

true

// load in footer

);

< 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

if ( ! is_cached( 'pwcc-style' ) &&

! is_http2() ) { print_style_inline( 'pwcc-style' ); wp_enqueue_script( 'pwcc-load-css' ); } Inline CSS

if ( ! is_cached( 'pwcc-style' ) &&

! is_http2() ) { print_style_inline( 'pwcc-style' ); wp_enqueue_script( 'pwcc-load-css' ); } Inline CSS pwcc.cc/wceu/rapidcss

< 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 : 1 px

dotted } b , strong { font-weight : bold } dfn { font-style : italic } h1 { font- size : 2 em ; margin : 0.67 em

0 } mark { background : #ff0 ; color : #000 }

< link

rel

"stylesheet"

href

"/style.css" /> Cached Stylesheet

< 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'

Everything you know about performance is now wrong and former best practices are now an anti-pattern and considered harmful.

Everything you know about performance is now

twice as complicated.

Thank you Peter Wilson • peterwilson.cc • @pwcc