Share
Embed
Transcript
155 slides
-
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Optimising PWA’s Michael
Gooding & Gareth Hughes -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Intro Agenda 1.
What is a PWA? 2. Measure performance of a PWA 3. Optimising App startup 4. Optimising within the App 5. Improve user experience -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Who are we?
Michael Gooding Gareth Hughes Intro Z S -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Avoid data theft
and downtime by extending the security perimeter outside the data-center and protect from increasing frequency, scale and sophistication of web attacks. Section 1: What is a PWA? Easy to launch Nice load screens Work offline (kind of) Can consume space BUT … -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Avoid data theft
and downtime by extending the security perimeter outside the data-center and protect from increasing frequency, scale and sophistication of web attacks. Section 1: What is a PWA? Simple Searchable Sharable Adaptable -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Avoid data theft
and downtime by extending the security perimeter outside the data-center and protect from increasing frequency, scale and sophistication of web attacks. Section 1: What is a PWA? PWA = Web + App Normal website + -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Avoid data theft
and downtime by extending the security perimeter outside the data-center and protect from increasing frequency, scale and sophistication of web attacks. Section 1: What is a PWA? • A built in browser proxy • JavaScript based • Bonus of push notifications • Cache assets on start up • Use cache when no network • Error handle when no cache and no network • And more….. -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Avoid data theft
and downtime by extending the security perimeter outside the data-center and protect from increasing frequency, scale and sophistication of web attacks. Section 1: What is a PWA? • Even in challenging network conditions • Standard page load timings important • As well as usability timings • 60fps rendering • No Jank • Responsive touch inputs -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Avoid data theft
and downtime by extending the security perimeter outside the data-center and protect from increasing frequency, scale and sophistication of web attacks. Section 1: What is a PWA? -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Avoid data theft
and downtime by extending the security perimeter outside the data-center and protect from increasing frequency, scale and sophistication of web attacks. Section 1: What is a PWA? TLS is a ranking index in it’s own right But TLS opens access to: • Service workers • Push notification API • H2 for performance • Other API’s • Web Background sync • Payment API -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Avoid data theft
and downtime by extending the security perimeter outside the data-center and protect from increasing frequency, scale and sophistication of web attacks. Section 1: What is a PWA? • Adaptive is also OK • Applies to Tablets as well as mobile • Viewport <meta> tags • Correct sized content (think images) • Big enough buttons • Manual checks still useful -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Avoid data theft
and downtime by extending the security perimeter outside the data-center and protect from increasing frequency, scale and sophistication of web attacks. Section 1: What is a PWA? -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measure
performance of a PWA Agenda • Types of monitoring • Metrics and best practice • RUM lab -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Types of monitoring
Section 2: Measuring performance of a PWA -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA Types of monitoring 1. Synthetic 1. Lighthouse 2. Webpagetest 3. Catchpoint / Rigor etc 2. Real User Monitoring 1. CRuX (free starting point) 2. mPulse (or other paid solution) 3. DIY -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA Lighthouse – Dev Tools or Command line -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA $ sudo npm install -g lighthouse $ lighthouse demo.pwa.akamaiworkshop.com -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Demo Section 2:
Measuring performance of a PWA -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA Webpagetest -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Demo Section 2:
Measuring performance of a PWA -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA Synthetic (Rigor) -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA CrUX -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Metrics and best
practice Section 2: Measuring performance of a PWA -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA Server 0.5s Total 10s Load 7s Render 2s Meaningful 4s -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA ” Performance is for users” -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA Real user Monitoring (mPulse) -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Performance is for
ALL users! Section 2: Measuring performance of a PWA -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA Index.html ~ line 16 <!-- Bootstrap core CSS --> <link href="css/bootstrap.min.css" rel="stylesheet"> <!-- Custom styles for this template --> <link href="css/jumbotron.css" rel="stylesheet"> <script> performance.mark('CSS’); </script> -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA Create user timing -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 2: Measuring
performance of a PWA -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab https://mpulselogin.soasta.com/ Username:
[email address] Password: Fluent2018 Check data from your app Review dashboards Create a custom timing -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Agenda • Manifest • Icon • Hero image / carousel • CSS • JS • Fonts -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Manifest Section 3:
Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup https://www.pwabuilder.com/ -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 { "dir": "ltr",
"lang": "English", "name": "Fluent Shop", "scope": "/", "display": "standalone", "start_url": "https://demo.pwa.akamaiworkshop.com/", "short_name": "Fluent Shop", "theme_color": "#93BE76", "description": "", "orientation": "any", "background_color": "#93BE76", "related_applications": [], "prefer_related_applications": false, "icons": [ { "src": "/img/icons/0ba00ee8-a3de-e472-3e4e-2a08830d5fb1.webPlatform.png", "sizes": "48x48", "type": "image/png" }, Manifest file Section 3: Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Be byte responsible
• Cache the file • Compress the file • Consider renaming the images • Limit the number of images (2-5) • Cache those images • Optimise the images Section 3: Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Icons Section 3:
Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Icon rendering on Moto G 24 x 24 300 x 300 -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup SVG & PNG on Moto G SVG PNG -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Hero Images Section
3: Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Hero Images and Carousels Hero Images and Carousels Defer Reduce weight -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Reduce weight of
images • Size * • Resize for device types • Resize for screen estate • Format • The basics (e.g. no png’s) • Browser specific formats • Quality • Baseline a good start • Intelligent automated solutions * See also responsive images Section 3: Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Defer loading of
images • Page events • Object events • User events Section 3: Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Loading the correct
image • Srcset & sizes • Simple size switching • Simple dpr switching • No mixing • Picture element • Combined support for • DPR • Size • Format Section 3: Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Reduce weight $ sudo apt-get install imagemagick [done] $ sudo apt-get install webp [done] $ cd var/www/html/img/carousel $ mkdir 400 800 1024 $ mogrify -path 400 -quality 80 -resize 400 *.jpg $ mogrify -path 400 -quality 80 -resize 400 -format webp *.jpg $ mogrify -path 800 -quality 80 -resize 800 *.jpg $ mogrify -path 800 -quality 80 -resize 800 -format webp *.jpg $ mogrify -path 1024 -quality 80 -resize 1024 *.jpg $ mogrify -path 1024 -quality 80 -resize 1024 -format webp *.jpg -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Index.html ~ line 85 <div class="carousel-inner"> <div class="carousel-item active"> <a href="product.html?pid=004"> <img class="d-block w-100" src="/img/carousel/hero1.jpg" alt="First slide"> </a> </div> <div class="carousel-item"> ... </div> ... </div> -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Index.html ~ line 88 <div class="carousel-item active"> <a href="product.html?pid=004"> <picture class="d-block w-100" alt="First slide" data-src=""> <source type="image/webp" srcset="/img/carousel/400/hero1.webp 400w, /img/carousel/800/hero1.webp 800w, /img/carousel/1024/hero1.webp 1024w" sizes="100vw"> <img src="/img/carousel/1024/hero1.jpg" srcset="/img/carousel/400/hero1.jpg 400w, /img/carousel/800/hero1.jpg 800w, /img/carousel/1024/hero1.jpg 1024w" sizes="100vw"> </picture> </a> </div> -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup <div class="carousel-item"> <a href="product.html?pid=002"> <picture class="d-block w-100" data-src="hero2" alt="Second slide"> </picture> </a> </div> Index.html ~ line 93, 98 & 103 -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Index.html ~ line 48 <body onload="lazyload()"> function lazyload(){ var x = document.getElementsByClassName("d-block w-100"); var i; for (i = 0; i < x.length; i++) { if (x[i].getAttribute("data-src").length != 0) { var fileName = x[i].src = x[i].getAttribute("data-src"); var src = document.createElement("source"); src.type = "image/webp"; src.srcset = "/img/carousel/400/"+fileName+".webp 400w, /img/carousel/800/"+fileName+".webp 800w, /img/carousel/1024/"+fileName+".webp 1024w"; src.sizes = "100vw"; x[i].appendChild(src) var img = document.createElement("img"); img.src = "/img/carousel/1024/hero2.jpg"; img.srcset = "/img/carousel/400/"+fileName+".jpg 400w, /img/carousel/800/"+fileName+".jpg 800w, /img/carousel/1024/"+fileName+".jpg 1024w"; img.sizes = "100vw"; x[i].appendChild(img) } } } -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Hero Images and Carousels Hero Images and Carousels Defer Reduce weight -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Hero Images and Carousels Hero Images and Carousels Defered Image weight -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab Optimise your
images Add a picture element Add lazy loading -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 CSS Section 3:
Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 CSS • Compress
• Minify • Think about your approach… • Initial performance – think about the critical path • In-app performance & cacheability – big bang Section 3: Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Critical Path Faster rendering Smaller payload Improved app start-up time Only used once Maintenance overhead Monolith Reusable Increased offload Easy to maintain Can delay render Sending more bytes -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup index.html home.min.css? Cache bootstrap.min.css Sw.js -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup pwabuilder-sw.js var preLoad = function(){ console.log('[PWA Builder] Install Event processing'); return caches.open('pwabuilder-offline').then(function(cache) { console.log('[PWA Builder] Cached index and offline page during Install'); return cache.addAll( [ '/index.html', '/offline.html', '/img/offline.png', '/css/bootstrap.min.css', '/css/jumbotron.css', '/js/jquery-3.2.1.slim.min.js', '/js/vendor/popper.min.js', '/js/bootstrap.min.js' ]); }); } -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup pwabuilder-sw.js self.addEventListener('fetch', function(event) { console.log('The service worker is serving the asset.'); if (event.request.url.match(/\.(css)$/)) { event.respondWith(returnFromCache(event.request).catch(function() { return checkResponse(event.request) })); } else { event.respondWith(checkResponse(event.request).catch(function() { return returnFromCache(event.request) })); } }); -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup pwabuilder-sw.js var returnFromCache = function(request){ return caches.open('pwabuilder-offline').then(function (cache) { return cache.match(request).then(function (matching) { if(!matching || matching.status == 404) { if (request.url.match(/\.(htm?l)$.*/)) { return cache.match('offline.html’) } if (request.url.match(/\.(jpe?g|png|gif|svg|webp)$/)) { return cache.match('/img/offline.png’) } if (request.url.match(/\.(css)$/)) { return cache.match('/css/bootstrap.min.css’) } } else { return matching } }); }); }; -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab Swap in
critical path CSS on the homepage Configure Service Worker to serve the monolith -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup PUSH! • Push critical resources • Use the “dead” time • https://shouldipush.com • https://canipush.com • Can be used with either strategy -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup /etc/apache2/sites-available/default-ssl.conf <LocationMatch ".*\.html"> Header add Link ”</css/bootstrap.min.css>;rel=preload;as=style" Header add Link "</css/jumbotron.css>;rel=preload;as=style" </LocationMatch> -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab Add Push
hints to Apache Configuration -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 JS Section 3:
Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup JavaScript best practice • Compress • Cache • Minify Async Defer -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 /critical.js /func.js /css
/html Section 3: Optimising App startup Synchronously loading func.js dns connect ssl request response render render -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 /critical.js /func.js /css
/html Section 3: Optimising App startup dns connect ssl request response Asynchronously loading fun.js render render async -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 /critical.js /func.js /css
/html Section 3: Optimising App startup dns connect ssl request response Defer the loading & execution of func.js render render defer -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Index.html ~ line 132 <!-- Bootstrap core JavaScript ================================================== --> <!-- Placed at the end of the document so the pages load faster --> <script src="js/jquery-3.2.1.slim.min.js"></script> <script src="js/vendor/popper.min.js"></script> <script src="js/bootstrap.min.js"></script> </body> </html> -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup Index.html ~ line 132 <!-- Bootstrap core JavaScript ================================================== --> <!-- Placed at the end of the document so the pages load faster --> <script src="js/jquery-3.2.1.slim.min.js" async></script> <script src="js/vendor/popper.min.js" defer></script> <script src="js/bootstrap.min.js" async></script> </body> </html> -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab Experiment adding
DEFER / ASYNC attributes to JS on PLP / PDP -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Fonts Section 3:
Optimising App startup -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 3: Optimising
App startup • Externally hosted • Self-hosted • Eliminate 3rd party on the render path • Greater control • Preload • Push -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab Add Preload
header for Google Font CSS Change CSS to self-hosted fonts Push Font Files Preload in Service Worker -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App Agenda • Rendering with h2 • Image optimisation • Service worker for caching • Preload content -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App Rendering (with h2) -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App H2 Recap • Multiplexing • Header compression • Server push -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App Rendering with h2 -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App H2 rendering best practice • Critical content from single domain • Defer non-critical content • Server push • Preload 3rd party content * * resource hints -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App Single domain -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App pushed -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App preloaded -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App Image optimisation -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App PLP Images 200 x 200 -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App $ cd var/www/html/products/images $ mkdir thumbs thumbsLQ $ mogrify -path thumbs -colorspace RGB -quality 90 -resize 400 *_1.jpg $ mogrify -path thumbsLQ -colorspace RGB -quality 20 -resize 400 *.jpg -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App <script id="prod-template" type="text/x-handlebars-template"> {{#each products}} <div class="col-md-4 text-center"> <img src="products/images/pid{{id}}_1.jpg" width="200px" /> <h4><a href="product.html#pid={{id}}">{{title}}</a></h4> <h3>${{price}}</h3> Products.html ~ line 58 -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App <script id="prod-template" type="text/x-handlebars-template"> {{#each products}} <div class="col-md-4 text-center"> <img src="products/images/thumbs/pid{{id}}_1.jpg" width="200px" /> <h4><a href="product.html#pid={{id}}">{{title}}</a></h4> <h3>${{price}}</h3> Products.html ~ line 58 -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App Quick size fix -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App <script id="prod-template" type="text/x-handlebars-template"> {{#each products}} <div class="col-md-4 text-center"> <img data-src="products/images/thumbs/pid{{id}}_1.jpg" width="200px" /> <h4><a href="product.html#pid={{id}}">{{title}}</a></h4> <h3>${{price}}</h3> Products.html ~ line 58 -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App function showProducts(){ products = document.getElementsByClassName("col-md-4 text-center"); for (i = 0; i < products.length; i++) { if(i >= (firstProduct -1) && i <= (lastProduct -1)) { products[i].style.display = 'block'; } else { document.getElementsByClassName("col-md-4 text- center")[i].style.display = 'none'; } } } /js/pagination.js~ line 63 -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App function showProducts(){ ... for (i = 0; i < products.length; i++) { if(i >= (firstProduct -1) && i <= (lastProduct -1)) { products[i].style.display = 'block'; /* lazy load images */ var divID = products[i].id; var imgID = divID.replace("div_", "img_"); if(document.getElementById(imgID).src == ’’){ document.getElementById(imgID).src = document.getElementById(imgID).getAttribute("data-src"); } } else { /js/pagination.js~ line 63 -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App Lazy loading -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab Create variant
images Update image source Add code to lazy load -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App Service worker for caching -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App What’s our Service Worker *doing*? …let’s take a look -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/ -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/ -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab Configure Service
Worker to Cache every file accessed -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 4: Optimising
within the App Let’s think about our native-like experience… • Browse the shop offline? • Add products to basket & purchase later -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab Add remaining
pages to preload in Service Worker Discover & preload primary image and thumbs -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience Agenda • 3rd parties • Offline measurement • Network Awareness • RAIL -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience 3rd Parties -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience SPOF -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience SPOF -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience SPOF <!-- Google Tag Manager --> <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-N5T323S');</script> <!-- End Google Tag Manager --> -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience 3rd Party best practice • Remove them all -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience 3rd Party best practice • Self host if possible • JS – async & defer where possible • Resource hints (preload & preconnect) • Measure performance • Measure impact • Impose SLA’s -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience 3rd Party Monitoring -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience 3rd Party Monitoring -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience 3rd Party impact -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience pwabuilder-sw.js self.addEventListener('fetch', function(event) { if(event.request.url.startsWith('https://demo.pwa.akamaiworkshop.com')) { event.respondWith(checkResponse(event.request).catch(function() { return returnFromCache(event.request) })); } else { event.respondWith(Promise.race([timeout(2000), fetch(event.request.url)])); } }); -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience pwabuilder-sw.js function timeout(delay) { return new Promise(function(resolve, reject) { setTimeout(function(){ resolve(new Response('', { status: 408, statusText: 'Request timed out.’ })); }, delay); }); } -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab Create custom
timer for 3rd party resource Introduce SLA’s for 3rd party content -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience Offline Measurement -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience • Google Analytics • https://garl.ink/offline-analytics • Collect & store offline • Replay when network available • We built a basic mPulse collector • Code Demo • Will be released • You can build your own! -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab Add Google
Analytics offline support -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience Network Awareness -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience • Not great for someone on limited bandwidth • Consider the cost… • https://whatdoesmysitecost.com/ -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience What if we could know what type of connection or the user’s preference? • Act differently for desktop/mobile • Desktop more likely to be on a fixed (unmetered/fast) connection • Detect if user has Chrome Data Saver enabled • Intercept requests and rewrite them • Use the Network API to discover the type of connection • Currently Draft… -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience pwabuilder-sw.js self.addEventListener('install', function(event) { if (navigator.userAgent.match(/(M|mobile).*$/)) { event.waituntil(minimalPreLoad()); } else { event.waituntil(preLoad()); } }); -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience pwabuilder-sw.js self.addEventListener('install', function(event) { if(navigator.connection.saveData) { event.waituntil(minimalPreLoad()); } else { event.waituntil(preLoad()); } }); -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience pwabuilder-sw.js self.addEventListener('fetch', function(event) { requestClone = event.request.clone(); if (navigator.connection.saveData && event.request.url.match(/(\/thumbs\/)/)) { return lowQualityImages(event.request); } event.respondWith(checkResponse(event.request).catch(function() { return returnFromCache(event.request)} )); }); var lowQualityImages = function(request) { //serve low quality images var url = request.url; newUrl = url.replace(/\/thumbs\//i, "/thumbsLQ/"); return fetch(newUrl); } -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Lab Add Network
Awareness for Preload Add LQ Thumbnails for Data Saver -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience pwabuilder-sw.js self.addEventListener('install', function(event) { if(navigator.connection && navigator.connection.type !== false) { //Network API data available if(navigator.connection.type == "ethernet" || "wifi" || "wimax") { //Fast, likely unmentered... preload all the things event.waituntil(preLoad()); } else { //Cellular or unable to detect... just give basic offline support event.waituntil(minimalPreLoad()); } } else { //Network API data not supported event.waitUntil(preLoad()); } }); -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience RAIL -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience 4 Parts of RAIL Source: https://developers.google.com/web/fundamentals/performance/rail -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience Response • Respond in under 50ms • Don’t block the user, make sure response is within 100ms • Provide feedback for anything else Source: https://developers.google.com/web/fundamentals/performance/rail -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience Animation • Do nothing where you can, do the minimum where you can’t • Use the 100ms response to pre-calculate expensive work • Target 10ms/frame, 6ms to render • Consider all types • visual animation • scrolling • dragging Source: https://developers.google.com/web/fundamentals/performance/rail -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience Idle • Use to complete deferred work • Keep work blocks <50ms to avoid blocking user input • User takes priority Source: https://developers.google.com/web/fundamentals/performance/rail -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience Load Test in conditions that match your users • 4G doesn’t always mean 4G • Focus on critical rendering path • 5s doesn’t mean everything • Source: https://developers.google.com/web/fundamentals/performance/rail -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Section 5: Improving
user experience Measuring RAIL in Dev Tools • Throttle your CPU • Throttle the network • View main thread activity • View main thread activities in a table to sort • Analyze frames per second (FPS) • Monitor CPU usage, JS heap size, DOM nodes, layouts per second, and more • Visualize network requests • Capture screenshots • View interactions • Find scroll performance issues • View paint events Source: https://developers.google.com/web/fundamentals/performance/rail -
Gareth Hughes @Brassic_lint | Michael Gooding @Michael_G_81 Summary Summary PWA’s
are 1. now mainstream Measure performance of a PWA 2. Optimise 3. App startup Optimise 4. within the App Consider 5. user experience