Slide 1

Slide 1 text

Quick Wins For Page Speed - Tejas Dinkar, Quintype

Slide 2

Slide 2 text

Quick Wins For Page Speed - Tejas Dinkar, Quintype Web Performance For Lazy People

Slide 3

Slide 3 text

about.me • Tejas Dinkar • I Make Terrible Jokes, Love Clojure + Javascript • Code Monkey - Quintype • @tdinkar • github.com/gja

Slide 4

Slide 4 text

about.talk • This talk is listed as a beginner -> intermediate talk • And I hope to cover a few quick things you can do without rewriting your entire app.

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

Why Do We Care? • We power quite a few of India’s most popular news sites • The digital news space is competitive, and bounce rates are high! • Many of our readers are from rural parts of the country

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

To reduce drop off 60% of your users will drop off in 4 seconds

Slide 10

Slide 10 text

For SEO As of July 2018

Slide 11

Slide 11 text

20% of the Turtles ate 80% of the Pizza Yes, it was Michaelangelo Note: Splinter not shown in picture

Slide 12

Slide 12 text

Not In Scope • gzip / brotli • add caching headers and serve from CDN • make your javascript non blocking • use tree shaking to reduce your bundle • React.hydrate instead of React.render

Slide 13

Slide 13 text

Not In Scope • Make everything a PWA with Isomorphic Rendering • Because this was already covered

Slide 14

Slide 14 text

7 Step Program for Fast Page Load

Slide 15

Slide 15 text

1 - Build A Chart

Slide 16

Slide 16 text

Here’s One I Made Earlier Trait Browsers For My Project. Please Don’t Copy

Slide 17

Slide 17 text

Here’s One I Made Earlier Trait Browsers The Good Optimize for Speed 90% - Last 5 Chrome, Firefox, Edge, Safari, Vivaldi For My Project. Please Don’t Copy

Slide 18

Slide 18 text

Here’s One I Made Earlier Trait Browsers The Good Optimize for Speed 90% - Last 5 Chrome, Firefox, Edge, Safari, Vivaldi The Bad Working, but slow 9% - Chrome 41+, IE11, UC Browser For My Project. Please Don’t Copy

Slide 19

Slide 19 text

Here’s One I Made Earlier Trait Browsers The Good Optimize for Speed 90% - Last 5 Chrome, Firefox, Edge, Safari, Vivaldi The Bad Working, but slow 9% - Chrome 41+, IE11, UC Browser The Ugly Don’t bother IE 6-10 For My Project. Please Don’t Copy

Slide 20

Slide 20 text

Be ruthless in your browser compatibility matrix

Slide 21

Slide 21 text

2 - Profile

Slide 22

Slide 22 text

3 - Profile

Slide 23

Slide 23 text

4 - Profile

Slide 24

Slide 24 text

5 - Profile

Slide 25

Slide 25 text

6 - Make a small change

Slide 26

Slide 26 text

7 - Profile

Slide 27

Slide 27 text

Profiling - Why? To protect you from the speaker of today’s talk convincing you that there are silver bullets out there!

Slide 28

Slide 28 text

Fast pages are all alike; every slow page is slow in its own way ~ Leo Tolstoy (probably)

Slide 29

Slide 29 text

Profiling - What? • First Page Load v/s Subsequent Load • Time to first Contentful paint v/s Time to Interactive • Above the fold v/s the full page

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Profiling - How?

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

Profiling - How?

Slide 34

Slide 34 text

Profiling - How?

Slide 35

Slide 35 text

Profiling - How?

Slide 36

Slide 36 text

Serving large asset with gzip is fine

Slide 37

Slide 37 text

Compression reduces network, but not processing

Slide 38

Slide 38 text

Sometimes the best Javascript is No Javascript

Slide 39

Slide 39 text

On To Some Quick Wins

Slide 40

Slide 40 text

Tell the browser what’s important 1: 2: ... 3: 4: ...

Slide 41

Slide 41 text

Tell the browser what’s important 1: 2: ... 3: 4: ... 5: 6: ...

Slide 42

Slide 42 text

Tell the browser what’s important 1: 2: ... 3: 4: ... 5: 6: ... 7: 8: 9:

Slide 43

Slide 43 text

Your browser is smart, but you can make it smarter!

Slide 44

Slide 44 text

Link Headers and H/2 push • Link: ; rel=preload; as=script • Link: ; rel=preload; as=fetch • • • CDNs will convert this to an HTTP2 push if it can • Fastly + Cloudflare both support this • Be careful, HTTP/2 is a mixed bag

Slide 45

Slide 45 text

Inline Your CSS • For years I’ve searched for the perfect way to do critical CSS • Then, I tried to just embed the entire CSS in page • In particular, this can improve your first time page load • If using a CSP header, remember to sign your CSS

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

CSS Modules • Delete unused CSS • Note: Not css-in-js • Remember to chunk your CSS /* header.css */ .logo { display: block; } // header.js import styles from './header.css' function Logo() { return ; }

Slide 48

Slide 48 text

Shrink Your CSS • Chrome has a ‘Coverage’ Tab, hidden way down there • Our target is to get Unused CSS down to 30%

Slide 49

Slide 49 text

Font CSS • Make sure you use woff2 (and fallback) • Choose your FOUT / FOIT strategy • Font-Display is your BFF! • But can cause multiple renders. Use fontfaceobserver.js for multiple fonts • Don’t use a different CSS for your fonts

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

Images • Images are the single largest contributor to weight (~55%) • Serve the right image size for the right device. Use imgix, ImageKit, thumbor, CF Polish, etc…. • And use the right format too! web-p! • Use img srcset to serve the multiple devices with a single HTML tag

Slide 53

Slide 53 text

Lazy Load Images • Lazy Load images below the fold • Do NOT LazyLoad anything above the fold • Use IntersectionObserver… It’s super easy!

Slide 54

Slide 54 text

Lazy Load Images 1: 3:

Slide 55

Slide 55 text

Lazy Load Images 1: 3: 4: 5: const observer = new IntersectionObserver(showImage, { 6: margin: '20px 0 100px', 7: });

Slide 56

Slide 56 text

Lazy Load Images 1: 3: 4: 5: const observer = new IntersectionObserver(showImage, { 6: margin: '20px 0 100px', 7: }); 8: 9: document.querySelectorAll("img[data-src]") 10: .forEach(x => observer.observe(x)) 11:

Slide 57

Slide 57 text

Lazy Load Images 1: 3: 4: 5: const observer = new IntersectionObserver(showImage, { 6: margin: '20px 0 100px', 7: }); 8: 9: document.querySelectorAll("img[data-src]") 10: .forEach(x => observer.observe(x)) 11: 12: function showImage(entries, observer) { 13: entries.forEach(entry => { 14: if(entry.isIntersecting) 15: entry.target.src = entry.target.getAttribute("data-src") 16: }) 17: } 18:

Slide 58

Slide 58 text

POLYFILLS

Slide 59

Slide 59 text

POLYFILLS

Slide 60

Slide 60 text

Polyfills

Slide 61

Slide 61 text

Conditional Polyfills import 'promise-polyfill'; import "babel-polyfill"; import 'whatwg-fetch';

Slide 62

Slide 62 text

Conditional Polyfills import 'promise-polyfill'; import "babel-polyfill"; import 'whatwg-fetch';

Slide 63

Slide 63 text

Conditional Polyfills 1: 2: if(!window.fetch || !window.Array.prototype.map || !window.Promise) { 3: s = document.createElement('script'); 4: s.type = 'text/javascript'; 5: s.src = '/path/to/polyfill.js'; 6: document.getElementsByTagName('head')[0].appendChild(s); 7: } 8: 9: 10:

Slide 64

Slide 64 text

This Chart Again Trait Browsers The Good Optimize for Speed 90% - Last 5 Chrome, Firefox, Edge, Safari, Vivaldi The Bad Working, but slow 9% - Chrome 41+, IE11, UC Browser The Ugly Don’t bother IE 6-10

Slide 65

Slide 65 text

Every time you add a library, check your bundle size

Slide 66

Slide 66 text

Wasting 16MB of RAM Across 225k Concurrent Users Wastes 3.6TB of RAM Globally!

Slide 67

Slide 67 text

Speaking of Libraries Let’s Play A Game

Slide 68

Slide 68 text

When I say It’s 2018 You Say You don’t need it anymore

Slide 69

Slide 69 text

lodash

Slide 70

Slide 70 text

Lodash _.map(array, a => a + 1) | v array.map(a => a + 1)

Slide 71

Slide 71 text

Lodash 1: // Don't do this 2: import _ from 'lodash'; 3: _.omit(myObject, 'lodash');

Slide 72

Slide 72 text

Lodash 1: // Don't do this 2: import _ from 'lodash'; 3: _.omit(myObject, 'lodash'); 4: 5: // Use a totally different, tiny library 6: import omit from 'object.omit'; 7: omit(myObject, 'lodash');

Slide 73

Slide 73 text

Lodash 1: // Don't do this 2: import _ from 'lodash'; 3: _.omit(myObject, 'lodash'); 4: 5: // Use a totally different, tiny library 6: import omit from 'object.omit'; 7: omit(myObject, 'lodash'); 8: 9: // Just import the right bit of lodash 10: import omit from 'lodash/omit'; 11: omit(myObject, 'lodash');

Slide 74

Slide 74 text

Lodash 1: // Don't do this 2: import _ from 'lodash'; 3: _.omit(myObject, 'lodash'); 4: 5: // Use a totally different, tiny library 6: import omit from 'object.omit'; 7: omit(myObject, 'lodash'); 8: 9: // Just import the right bit of lodash 10: import omit from 'lodash/omit'; 11: omit(myObject, 'lodash'); 12: 13: // Works with Webpack 4 14: import {omit} from 'lodash'; 15: omit(myObject, 'lodash');

Slide 75

Slide 75 text

jQuery especially the selector and bind bits

Slide 76

Slide 76 text

jQuery 1: const masthead = $(".masthead a"); 2: 3: masthead.bind("click", function(e) { 4: e.preventDefault() 5: 6: masthead.addClass("loading"); 7: masthead.hide(500); 8: 9: $.getJson("/foo.json", () => masthead.removeClass("loading")) 10: })

Slide 77

Slide 77 text

!jQuery 1: const masthead = document.querySelector(".masthead a"); 2: 3: masthead.addEventListener("click", function(e) { 4: e.preventDefault(); 5: 6: masthead.classList.add("loading"); 7: masthead.style.height = 0; // Use CSS Transition to shrink 8: 9: fetch("/foo.json") 10: .then(res => res.json()) 11: .then(() => masthead.classList.remove("loading")); 12: })

Slide 78

Slide 78 text

jQuery - caveats • $(‘.x’).bind is on element, use querySelectorAll.forEach() • loads of caveats on querySelectorAll • fetch works slightly differently from XHR • jQuery supports more browsers than if you write it yourself :-p

Slide 79

Slide 79 text

moment and other libraries that come loaded with locales

Slide 80

Slide 80 text

Final Thoughts • Though we were already a PWA, that wasn’t nearly enough to get us to a sub second page load • We actually brought our FCP down from 3500 to 900 ms, and saw a 35% increase in traffic • This is a continuous journey. Perf day should be every day • Measure your important metrics as part of your CI

Slide 81

Slide 81 text

Links • Chrome Dev Podcast - HTTP 203 https:// developers.google.com/web/shows/http203/ • https://chrisbateman.github.io/webpack-visualizer/ • https://cssstats.com

Slide 82

Slide 82 text

` • Twitter - @tdinkar • [email protected] • github.com/gja