Optimiser les performances d'une webapp

D3bcad37b1ec0fc8ecdeb199e54a61e4?s=47 Dev-Mind
April 05, 2017

Optimiser les performances d'une webapp

Avec les outils actuels, développer une application web (grand public ou privée), avec du JS en front et du Java en backend est de plus en plus rapide. Les premiers hics peuvent survenir le jour où vous basculez cette application en production.

Mon but est de vous montrer dans cette session, comment optimiser une webapp quelque soit les solutions techniques utilisées côté front ou côté serveur. Mes exemples se basent sur une application SpringBoot avec un frontend en JS (sans framework particulier) mais ceci est peu important. Nous allons nous focaliser sur les concepts qui restent vrais quelque soit les langages.

Nous verrons les différentes étapes pour améliorer la rapidité d'une application au premier chargement (load time), en mode offline, comment jouer sur le critical rendering... Au niveau des solutions nous parlerons cache, asynchronisme, services workers...

Conférence donnée à Devoxxfr http://cfp.devoxx.fr/2017/speaker/guillaume_ehret

Besoin d'une formation sur le sujet rendez vous sur https://www.dev-mind.fr

D3bcad37b1ec0fc8ecdeb199e54a61e4?s=128

Dev-Mind

April 05, 2017
Tweet

Transcript

  1. 5.

    #WebPerformance / 6 avril 2017 @guillaumeehret avec des crêpes et

    du coeur 20 et 21 avril à Lyon https://mixitconf.org/
  2. 6.

    #WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril

    2017 @guillaumeehret Pourquoi une webapp doit être performante ?
  3. 9.

    #WebPerformance / 6 avril 2017 @guillaumeehret > 3 sec sur

    mobile ⇒ 57% des users en moins 0 : 03 DoubleClick, “The Need for Mobile Speed”, September 2016 https://giphy.com
  4. 13.

    #WebPerformance / 6 avril 2017 @guillaumeehret 2010 2017 2016 2015

    2014 2013 2012 2011 http://httparchive.org mars 2017
  5. 15.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 Mb en 2017

    Wifi 30Mb/s ⇒ 0.5 sec 4G 4Mb/s ⇒ 5 sec H+ 1.5Mb/s ⇒ 10 sec 3G 750kb/s ⇒ 25 sec Webpagetest.org, , February 2016
  6. 16.

    #WebPerformance / 6 avril 2017 @guillaumeehret Webpagetest.org, , February 2016

    Temps mobile 10s 3/4 19s moy 200 moy Les performances sur mobile ne sont pas toujours au rendez vous
  7. 17.

    #WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril

    2017 @guillaumeehret Et les applications d’entreprise ?
  8. 21.

    #WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril

    2017 @guillaumeehret Que faire pour créer des webapps performantes ?
  9. 29.

    #WebPerformance / 6 avril 2017 @guillaumeehret loadtime https://monsite/ HTML parsing

    parsing compile render JavaScript Autres CSS render JavaScript Autres CSS ... 1
  10. 30.

    #WebPerformance / 6 avril 2017 @guillaumeehret first paint https://monsite/ parsing

    parsing compile render JavaScript Autres CSS render JavaScript Autres CSS ... 1 HTML
  11. 34.

    #WebPerformance / 6 avril 2017 @guillaumeehret Mes outils pour mesurer

    Webpagetest >> Pagespeed Insight >> Browser developper tools ... 1
  12. 39.

    #WebPerformance / 6 avril 2017 @guillaumeehret Avant de commencer 2

    7.4s first paint 18.2s loadtime Sans optim 1.6Mb size
  13. 42.

    #WebPerformance / 6 avril 2017 @guillaumeehret <html> <head> <script .../>

    <body> <script .../> </body </html> JavaScript HTML 2
  14. 45.

    #WebPerformance / 6 avril 2017 @guillaumeehret Ordre de définition des

    scripts JS 2 7.4s first paint 18.2s loadtime Sans optim 1.6Mb size 6.4s first paint 18.2s loadtime 1.6Mb size -13.5% first paint 0% loadtime 0% size
  15. 49.

    #WebPerformance / 6 avril 2017 @guillaumeehret 2 HTTP2 et Java

    1. Container compatible Jetty 9.2, Undertow (JBoss) 1.3, Tomcat > 8.5 2. Activer le mode HTTP 2 3. Avoir un certificat 4. Ajouter le jar ALPN au jdk (lib pour Jdk < 9)
  16. 50.

    #WebPerformance / 6 avril 2017 @guillaumeehret HTTP 2 2 6.4s

    first paint 18.2s loadtime Ordre JS 1.6Mb size 6.4s first paint 18.1s loadtime 1.6Mb size 0% first paint -0.5% loadtime 0% size
  17. 54.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 Minification ressources txt

    JavaScript HTML sur mon exemple -22% -51% -26% CSS
  18. 56.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 public class SessionDto

    { public String title; public String summary; public String lang; public String format; public String description; public Instant start; public Instant room; ... } des DTO qui collent à l’API
  19. 57.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 public class SessionDto

    { public String title; public String summary; public String lang; public String format; public String description; public Instant start; public Instant room; ... } public class SessionListDto { public String title; public String summary; ... } des DTO qui collent à l’API
  20. 59.

    #WebPerformance / 6 avril 2017 @guillaumeehret Minification du texte 6.4s

    first paint 18.1s loadtime HTTP2 1.6Mb size 5.5s first paint 15.4s loadtime 1.3Mb size -14% first paint -15% loadtime -19% size 3
  21. 60.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 Le texte se

    compresse CSS JavaScript HTML JSON les navigateurs acceptent le gzip
  22. 61.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 Le texte se

    compresse JavaScript HTML JSON server: compression: enabled: true mime-types: application/json,text/html,text/css,application/javascript min-response-size: 2048 CSS
  23. 62.

    #WebPerformance / 6 avril 2017 @guillaumeehret Compression du texte 5.5s

    first paint 15.4s loadtime Minification 1.3Mb size 1.5s first paint 10.8s loadtime 940Kb size -72% first paint -30% loadtime -28% size 3
  24. 67.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 Material Design Lite

    185kb 228kb 203kb 20kb Les frameworks CSS CSS CSS +JS CSS +JS CSS +JS CSS JS JS JQuery 69kb JQuery 69kb
  25. 68.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 Quelques astuces Modularité

    frameworks Apprenez CSS CSS is awesome de Igor Laborie Nettoyage automatique avec uncss CSS
  26. 69.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 UnCSS return gulp.src(`${paths.main}/**/*.css`)

    .pipe($.if('*.css', $.uncss({ html : [ `${paths.main}/*.html`, `${paths.main}/component/**/*.html`, `${paths.main}/component/**/*.js`] }))) .pipe(gulp.dest(`${paths.dist}/styles`)); CSS
  27. 70.

    #WebPerformance / 6 avril 2017 @guillaumeehret Utilisation UnCSS 1.5s first

    paint 10.8s loadtime Compression 940Kb size 0.5s first paint 10.4s loadtime 920Kb size -67% first paint -3.7% loadtime -2.1% size 3 CSS
  28. 72.

    #WebPerformance / 6 avril 2017 @guillaumeehret Compression imagemin 0.5s first

    paint 10.4s loadtime UnCss 920Kb size 0.5s first paint 8.5s loadtime 735Kb size 0% first paint -18% loadtime -20% size 3 Images
  29. 76.

    #WebPerformance / 6 avril 2017 @guillaumeehret <picture> la balise perdue

    3 Des images responsives en HTML avec la balise <picture> et la propriété srcset Images
  30. 78.

    #WebPerformance / 6 avril 2017 @guillaumeehret propriété srcset 3 <img

    src="img/mixit/mixit-amphi_640.jpg" srcset="img/mixit/mixit-amphi_640.jpg 640w, img/mixit/mixit-amphi_1024.jpg 1024w, img/mixit/mixit-amphi_2048.jpg"> la largeur de la fenêtre nombre entier suivi par 'w' (640w), par défaut c’est l’infini la densité de pixel nombre entier suivi par 'x' (2x), par défaut c’est 1x. Images
  31. 79.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 <picture> <source srcset="img/mixit/mixit-amphi_640.webp

    640w, img/mixit/mixit-amphi_1024.webp 1024w, img/mixit/mixit-amphi_2048.webp" type="image/webp"/> <source srcset="img/mixit/mixit-amphi_640.jpg 640w, img/mixit/mixit-amphi_1024.jpg 1024w, img/mixit/mixit-amphi_2048.jpg"/> <img src="img/mixit/mixit-amphi_640.jpg" alt="Mix-IT amphi"> </picture> Images
  32. 80.

    #WebPerformance / 6 avril 2017 @guillaumeehret format webp 3 0.5s

    first paint 8.5s loadtime imagemin 735Kb size 0.5s first paint 6.7s loadtime 572Kb size 0% first paint -21% loadtime -22% size Images
  33. 82.

    #WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril

    2017 @guillaumeehret Utilisez le moins de font possible 3
  34. 83.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 Fonts Format Extension

    Exemple Font Roboto Compression EOT .eot 179 ko TrueType .ttf 179 ko WOFF .woff 89 ko >10 WOFF2 .woff2 64ko 30% + que WOFF >10 >10 SVG .svg 743 ko IE Edge Firefox Chrome Safari Opera Opera Mini Android Browser iOS Safari Chrome for Android
  35. 84.

    #WebPerformance / 6 avril 2017 @guillaumeehret 3 @font-face { font-family:

    Roboto; src: local('Roboto'), url(../fonts/Roboto-Regular.woff2) format('woff2'), url(../fonts/Roboto-Regular.woff) format('woff'), url(../fonts/Roboto-Regular.eot), url(../fonts/Roboto-Regular.ttf) format('truetype'), url(../fonts/Roboto-Regular.svg#Roboto) format('svg'); font-weight: 300; font-style: normal } body { font-family: Roboto, Arial, sans-serif; } Fonts
  36. 85.

    #WebPerformance / 6 avril 2017 @guillaumeehret Utiliser un CDN 3

    <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet"> Fonts
  37. 86.

    #WebPerformance / 6 avril 2017 @guillaumeehret CDN pour les fonts

    3 0.5s first paint 6.7s loadtime webp 572Kb size 440ms first paint 3.4s loadtime 231Kb size -12% first paint -49% loadtime -59% size Fonts
  38. 88.

    #WebPerformance / 6 avril 2017 @guillaumeehret Polyfill sur CDN 3

    <script src="https://cdn.polyfill.io/v2/polyfill.min.js"> </script> Size (min) 1370 8212 464 26430 6652 Size (min+gz) 514 2435 285 8497 2018 JavaScript
  39. 89.

    #WebPerformance / 6 avril 2017 @guillaumeehret CDN JS 3 440ms

    first paint 3.4s loadtime CDN font 231Kb size 440ms first paint 2.9s loadtime 200Kb size 0% first paint -15% loadtime -13% size JavaScript
  40. 90.

    #WebPerformance / 6 avril 2017 @guillaumeehret Mais encore 3 Tree

    shaking SSR Code splitting (modules) Pré compilation ... JavaScript
  41. 92.

    #WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril

    2017 @guillaumeehret La ressource la plus rapide et la mieux optimisée est une ressource qui n'est pas envoyée. 4
  42. 94.

    #WebPerformance / 6 avril 2017 @guillaumeehret Cache serveur Cloud base

    de données ou I/O Temps fluctuant Abtraction Spring @Cacheable 4
  43. 103.

    #WebPerformance / 6 avril 2017 @guillaumeehret Refresh / Cache 440ms

    first paint 2.9s loadtime First load 200Kb size 427ms first paint 700ms loadtime 18Kb size -3% first paint -75% loadtime -91% size 4
  44. 107.
  45. 111.

    #WebPerformance / 6 avril 2017 @guillaumeehret 4 5 var worker

    = new Worker('doWork.js'); worker.addEventListener('message', (e) => { console.log('Worker said: ', e.data); }, false); worker.postMessage('Hello World'); self.addEventListener('message',(e) => { self.postMessage(e.data); }, false); doWork.js
  46. 114.

    #WebPerformance / 6 avril 2017 @guillaumeehret Service worker 5 sw-precache

    module node générant la configuration sw-toolbox lib JS qui fournit des utilitaires pour gérer le cache avec différentes stratégies : networkFirst, cacheFirst, fastest, cacheOnly, networkOnly
  47. 115.

    #WebPerformance / 6 avril 2017 @guillaumeehret 5 SW cache JS

    networkFirst cacheFirst fastest cacheOnly networkOnly
  48. 116.

    #WebPerformance / 6 avril 2017 @guillaumeehret 5 gulp.task('generate-service-worker', function(callback) {

    let config = { cacheId: 'dev-mind', runtimeCaching: [{ urlPattern: '/(.*)', handler: 'networkFirst', options : { networkTimeoutSeconds: 2, maxAgeSeconds: 43200 } }], staticFileGlobs: [ `${paths.dist}/**/*.{js,html,css,png,jpg,json,gif,svg,webp,woff2}`], stripPrefix: `${paths.dist}/`, verbose: true }; swPrecache.write(`${paths.tmp}/service-worker.js`, config, callback); });
  49. 117.

    #WebPerformance / 6 avril 2017 @guillaumeehret 5 if ('serviceWorker' in

    navigator) { navigator .serviceWorker .register('service-worker.js') .then(registration => { if (typeof registration.update === 'function') { registration.update(); } }) .catch(function(e) { console.error('Error during SW registration:', e); }); }
  50. 120.

    #WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril

    2017 @guillaumeehret Charger le plus important tout de suite et le reste plus tard
  51. 122.

    #WebPerformance / 6 avril 2017 @guillaumeehret 6 preload <link rel="preload"

    href="styles/app.css" as="style" onload="this.rel='stylesheet'"> <link rel="preload" href="/session/session.html" as="document"> <link rel="preload" href="/app.bundle.js" as="script">
  52. 124.

    #WebPerformance / 6 avril 2017 @guillaumeehret prefetch 6 <link rel="prefetch"

    href="https://fonts.googleapis.com/css?family=Roboto:400" onload="this.rel='stylesheet'">
  53. 125.

    #WebPerformance / 6 avril 2017 @guillaumeehret preload / prefecth 440ms

    first paint 2.9s loadtime First load 200Kb size 300ms first paint 2.9s loadtime 200Kb size -31% first paint 0% loadtime 0% size 4
  54. 127.

    #WebPerformance / 6 avril 2017 @guillaumeehret Notre objectif first load

    refresh offline 1 < 1s 7.4s first paint 18.2s loadtime 1.6Mb size Départ
  55. 128.

    #WebPerformance / 6 avril 2017 @guillaumeehret Notre objectif first load

    refresh offline 1 < 1s 300ms first paint 2.9s loadtime 200Kb size 220ms 700ms 18Kb first paint loadtime size 17ms 1.2s 0Kb first paint loadtime size 7.4s first paint 18.2s loadtime 1.6Mb size Départ
  56. 130.

    #WebPerformance / 6 avril 2017 @guillaumeehret Référence https://developers.google.com/web/fundamentals/performance https://github.com/ben-eb/gulp-uncss https://github.com/filamentgroup/loadCSS

    https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf https://nolanlawson.github.io/frontendday-2016/#1 https://www.youtube.com/watch?v=RWLzUnESylc https://github.com/GoogleChrome/sw-precache https://github.com/GoogleChrome/sw-toolbox https://developer.mozilla.org/fr/docs/Web/API/ServiceWorker https://jakearchibald.com/2014/offline-cookbook/
  57. 131.

    #WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril

    2017 @guillaumeehret First do it, then do it right, then do it better... Addy Osmani