Slide 1

Slide 1 text

#DevoxxFR Optimiser les performances d’une webapp Guillaume EHRET @guillaumeehret #WebPerformance Jeudi 6 avril 2017

Slide 2

Slide 2 text

#WebPerformance / 6 avril 2017 @guillaumeehret Guillaume EHRET @guillaumeehret #WebPerformance Optimiser les performances d’une webapp

Slide 3

Slide 3 text

#WebPerformance / 6 avril 2017 @guillaumeehret Dev-Mind https://www.dev-mind.fr

Slide 4

Slide 4 text

#WebPerformance / 6 avril 2017 @guillaumeehret https://www.dev-mind.fr Développement Formations

Slide 5

Slide 5 text

#WebPerformance / 6 avril 2017 @guillaumeehret avec des crêpes et du coeur 20 et 21 avril à Lyon https://mixitconf.org/

Slide 6

Slide 6 text

#WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril 2017 @guillaumeehret Pourquoi une webapp doit être performante ?

Slide 7

Slide 7 text

#WebPerformance / 6 avril 2017 @guillaumeehret 1 2 3 https://giphy.com

Slide 8

Slide 8 text

#WebPerformance / 6 avril 2017 @guillaumeehret Mobile First mars 2017

Slide 9

Slide 9 text

#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

Slide 10

Slide 10 text

#WebPerformance / 6 avril 2017 @guillaumeehret

Slide 11

Slide 11 text

#WebPerformance / 6 avril 2017 @guillaumeehret

Slide 12

Slide 12 text

#WebPerformance / 6 avril 2017 @guillaumeehret

Slide 13

Slide 13 text

#WebPerformance / 6 avril 2017 @guillaumeehret 2010 2017 2016 2015 2014 2013 2012 2011 http://httparchive.org mars 2017

Slide 14

Slide 14 text

#WebPerformance / 6 avril 2017 @guillaumeehret 3 Mb en 2017 Wifi 30Mb/s ⇒ 0.5 sec

Slide 15

Slide 15 text

#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

Slide 16

Slide 16 text

#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

Slide 17

Slide 17 text

#WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril 2017 @guillaumeehret Et les applications d’entreprise ?

Slide 18

Slide 18 text

#WebPerformance / 6 avril 2017 @guillaumeehret https://giphy.com

Slide 19

Slide 19 text

#WebPerformance / 6 avril 2017 @guillaumeehret

Slide 20

Slide 20 text

#WebPerformance / 6 avril 2017 @guillaumeehret

Slide 21

Slide 21 text

#WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril 2017 @guillaumeehret Que faire pour créer des webapps performantes ?

Slide 22

Slide 22 text

#WebPerformance / 6 avril 2017 @guillaumeehret 1 Mesurer Transport Limiter 2 3 4 Cache Offline Anticiper 5 6

Slide 23

Slide 23 text

#WebPerformance / 6 avril 2017 @guillaumeehret 1 Mesurer Transport Limiter 2 3 4 Cache Offline Anticiper 5 6

Slide 24

Slide 24 text

#WebPerformance / 6 avril 2017 @guillaumeehret https://monsite/ 1

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

#WebPerformance / 6 avril 2017 @guillaumeehret CSS parsing compile render parsing JavaScript Autres 1

Slide 27

Slide 27 text

#WebPerformance / 6 avril 2017 @guillaumeehret parsing compile render JavaScript Autres parsing 1 CSS

Slide 28

Slide 28 text

#WebPerformance / 6 avril 2017 @guillaumeehret render JavaScript Autres 1 CSS

Slide 29

Slide 29 text

#WebPerformance / 6 avril 2017 @guillaumeehret loadtime https://monsite/ HTML parsing parsing compile render JavaScript Autres CSS render JavaScript Autres CSS ... 1

Slide 30

Slide 30 text

#WebPerformance / 6 avril 2017 @guillaumeehret first paint https://monsite/ parsing parsing compile render JavaScript Autres CSS render JavaScript Autres CSS ... 1 HTML

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

#WebPerformance / 6 avril 2017 @guillaumeehret Notre objectif first load refresh 1 < 1s

Slide 33

Slide 33 text

#WebPerformance / 6 avril 2017 @guillaumeehret Notre objectif first load refresh offline 1 < 1s

Slide 34

Slide 34 text

#WebPerformance / 6 avril 2017 @guillaumeehret Mes outils pour mesurer Webpagetest >> Pagespeed Insight >> Browser developper tools ... 1

Slide 35

Slide 35 text

#WebPerformance / 6 avril 2017 @guillaumeehret 1

Slide 36

Slide 36 text

#WebPerformance / 6 avril 2017 @guillaumeehret Mobile Cache Throttling 3G 1

Slide 37

Slide 37 text

#WebPerformance / 6 avril 2017 @guillaumeehret 18.2s Load time loadtime 1 1.6Mb Size size

Slide 38

Slide 38 text

#WebPerformance / 6 avril 2017 @guillaumeehret first paint 1 7.4s first paint

Slide 39

Slide 39 text

#WebPerformance / 6 avril 2017 @guillaumeehret Avant de commencer 2 7.4s first paint 18.2s loadtime Sans optim 1.6Mb size

Slide 40

Slide 40 text

#WebPerformance / 6 avril 2017 @guillaumeehret 1 Mesurer Transport Limiter 2 3 4 Cache Offline Anticiper 5 6 2

Slide 41

Slide 41 text

#WebPerformance / 6 avril 2017 @guillaumeehret CSS JavaScript Autres HTML 2

Slide 42

Slide 42 text

#WebPerformance / 6 avril 2017 @guillaumeehret <body> <script .../> </body </html> JavaScript HTML 2

Slide 43

Slide 43 text

#WebPerformance / 6 avril 2017 @guillaumeehret 1 7.4s first paint 2

Slide 44

Slide 44 text

#WebPerformance / 6 avril 2017 @guillaumeehret 2 6.4s first paint

Slide 45

Slide 45 text

#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

Slide 46

Slide 46 text

#WebPerformance / 6 avril 2017 @guillaumeehret 2

Slide 47

Slide 47 text

#WebPerformance / 6 avril 2017 @guillaumeehret 2

Slide 48

Slide 48 text

#WebPerformance / 6 avril 2017 @guillaumeehret 2 HTTP2 côté client

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

#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

Slide 51

Slide 51 text

#WebPerformance / 6 avril 2017 @guillaumeehret 1 Mesurer Transport Limiter 2 3 4 Cache Offline Anticiper 5 6 2 3

Slide 52

Slide 52 text

#WebPerformance / 6 avril 2017 @guillaumeehret 3 https://giphy.com

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

#WebPerformance / 6 avril 2017 @guillaumeehret 3 Minification ressources txt JavaScript HTML sur mon exemple -22% -51% -26% CSS

Slide 55

Slide 55 text

#WebPerformance / 6 avril 2017 @guillaumeehret 3 Le JSON est aussi du texte JSON

Slide 56

Slide 56 text

#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

Slide 57

Slide 57 text

#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

Slide 58

Slide 58 text

#WebPerformance / 6 avril 2017 @guillaumeehret 3 Le JSON est aussi du texte -80% JSON

Slide 59

Slide 59 text

#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

Slide 60

Slide 60 text

#WebPerformance / 6 avril 2017 @guillaumeehret 3 Le texte se compresse CSS JavaScript HTML JSON les navigateurs acceptent le gzip

Slide 61

Slide 61 text

#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

Slide 62

Slide 62 text

#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

Slide 63

Slide 63 text

#WebPerformance / 6 avril 2017 @guillaumeehret CSS JavaScript Autres HTML 3

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

#WebPerformance / 6 avril 2017 @guillaumeehret CSS 3

Slide 66

Slide 66 text

#WebPerformance / 6 avril 2017 @guillaumeehret 3 https://giphy.com CSS

Slide 67

Slide 67 text

#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

Slide 68

Slide 68 text

#WebPerformance / 6 avril 2017 @guillaumeehret 3 Quelques astuces Modularité frameworks Apprenez CSS CSS is awesome de Igor Laborie Nettoyage automatique avec uncss CSS

Slide 69

Slide 69 text

#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

Slide 70

Slide 70 text

#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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

#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

Slide 73

Slide 73 text

#WebPerformance / 6 avril 2017 @guillaumeehret Préférez le vectoriel 3 svg png, jpg Images

Slide 74

Slide 74 text

#WebPerformance / 6 avril 2017 @guillaumeehret Jpeg XR 3 Images

Slide 75

Slide 75 text

#WebPerformance / 6 avril 2017 @guillaumeehret Webp 3 Images

Slide 76

Slide 76 text

#WebPerformance / 6 avril 2017 @guillaumeehret la balise perdue 3 Des images responsives en HTML avec la balise et la propriété srcset Images

Slide 77

Slide 77 text

#WebPerformance / 6 avril 2017 @guillaumeehret 3 Images Images

Slide 78

Slide 78 text

#WebPerformance / 6 avril 2017 @guillaumeehret propriété srcset 3 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

Slide 79

Slide 79 text

#WebPerformance / 6 avril 2017 @guillaumeehret 3 Mix-IT amphi Images

Slide 80

Slide 80 text

#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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

#WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril 2017 @guillaumeehret Utilisez le moins de font possible 3

Slide 83

Slide 83 text

#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

Slide 84

Slide 84 text

#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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

#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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

#WebPerformance / 6 avril 2017 @guillaumeehret Polyfill sur CDN 3 Size (min) 1370 8212 464 26430 6652 Size (min+gz) 514 2435 285 8497 2018 JavaScript

Slide 89

Slide 89 text

#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

Slide 90

Slide 90 text

#WebPerformance / 6 avril 2017 @guillaumeehret Mais encore 3 Tree shaking SSR Code splitting (modules) Pré compilation ... JavaScript

Slide 91

Slide 91 text

#WebPerformance / 6 avril 2017 @guillaumeehret 1 Mesurer Transport Limiter 2 3 4 Cache Offline Anticiper 5 6 2 4 3

Slide 92

Slide 92 text

#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

Slide 93

Slide 93 text

#WebPerformance / 6 avril 2017 @guillaumeehret 4 App Data

Slide 94

Slide 94 text

#WebPerformance / 6 avril 2017 @guillaumeehret Cache serveur Cloud base de données ou I/O Temps fluctuant Abtraction Spring @Cacheable 4

Slide 95

Slide 95 text

#WebPerformance / 6 avril 2017 @guillaumeehret Cache ressource 4 Browser Server Cache Request

Slide 96

Slide 96 text

#WebPerformance / 6 avril 2017 @guillaumeehret 4 Browser Cache Server Response

Slide 97

Slide 97 text

#WebPerformance / 6 avril 2017 @guillaumeehret 4 Browser Cache Server Response

Slide 98

Slide 98 text

#WebPerformance / 6 avril 2017 @guillaumeehret 4 Browser Server Cache Si max-age n’est pas dépassé

Slide 99

Slide 99 text

#WebPerformance / 6 avril 2017 @guillaumeehret 4 Browser Cache Server Response

Slide 100

Slide 100 text

#WebPerformance / 6 avril 2017 @guillaumeehret 4 Browser Server Cache Si max-age n’est pas dépassé

Slide 101

Slide 101 text

#WebPerformance / 6 avril 2017 @guillaumeehret 4 Browser Server Cache Si max-age est dépassé Request

Slide 102

Slide 102 text

#WebPerformance / 6 avril 2017 @guillaumeehret 4 Browser Cache Server Response 304

Slide 103

Slide 103 text

#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

Slide 104

Slide 104 text

#WebPerformance / 6 avril 2017 @guillaumeehret 1 Mesurer Transport Limiter 2 3 4 Cache Offline Anticiper 5 6 2 4 3 5

Slide 105

Slide 105 text

#WebPerformance / 6 avril 2017 @guillaumeehret 5 https://giphy.com

Slide 106

Slide 106 text

#WebPerformance / 6 avril 2017 @guillaumeehret 4 5

Slide 107

Slide 107 text

#WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril 2017 @guillaumeehret Services workers 4 5

Slide 108

Slide 108 text

#WebPerformance / 6 avril 2017 @guillaumeehret 4 5

Slide 109

Slide 109 text

#WebPerformance / 6 avril 2017 @guillaumeehret Web workers 4 5

Slide 110

Slide 110 text

#WebPerformance / 6 avril 2017 @guillaumeehret 4 5

Slide 111

Slide 111 text

#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

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

#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

Slide 115

Slide 115 text

#WebPerformance / 6 avril 2017 @guillaumeehret 5 SW cache JS networkFirst cacheFirst fastest cacheOnly networkOnly

Slide 116

Slide 116 text

#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); });

Slide 117

Slide 117 text

#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); }); }

Slide 118

Slide 118 text

#WebPerformance / 6 avril 2017 @guillaumeehret 5

Slide 119

Slide 119 text

#WebPerformance / 6 avril 2017 @guillaumeehret 1 Mesurer Transport Limiter 2 3 4 Cache Offline Anticiper 5 6

Slide 120

Slide 120 text

#WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril 2017 @guillaumeehret Charger le plus important tout de suite et le reste plus tard

Slide 121

Slide 121 text

#WebPerformance / 6 avril 2017 @guillaumeehret 6 preload

Slide 122

Slide 122 text

#WebPerformance / 6 avril 2017 @guillaumeehret 6 preload

Slide 123

Slide 123 text

#WebPerformance / 6 avril 2017 @guillaumeehret prefetch 6

Slide 124

Slide 124 text

#WebPerformance / 6 avril 2017 @guillaumeehret prefetch 6

Slide 125

Slide 125 text

#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

Slide 126

Slide 126 text

#WebPerformance / 6 avril 2017 @guillaumeehret 1 Mesurer Transport Limiter 2 3 4 Cache Offline Anticiper 5 6

Slide 127

Slide 127 text

#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

Slide 128

Slide 128 text

#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

Slide 129

Slide 129 text

#WebPerformance / 6 avril 2017 @guillaumeehret https://github.com/Dev-Mind/devoxx2017

Slide 130

Slide 130 text

#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/

Slide 131

Slide 131 text

#WebPerformance / 6 avril 2017 @guillaumeehret #WebPerformance / 6 avril 2017 @guillaumeehret First do it, then do it right, then do it better... Addy Osmani

Slide 132

Slide 132 text

#WebPerformance / 6 avril 2017 @guillaumeehret https://github.com/Dev-Mind/devoxx2017 Thanks