Des quickwins pour booster votre application !
Jonathan Hervieux @djow__
#DevoxxFR
-75%
encore 14m39s !
Indicateurs de performance, les web vitals
1. Du vocabulaire
- FCP (First Contentful Paint)
- TTFB (Time To First Byte)
1. Du vocabulaire
- TBT (Total Blocking Time)
- TTI (Time To Interactive)
1. Du vocabulaire
1. Du vocabulaire
1. Du vocabulaire
✔️
✔️
Comment on les mesure ?
❓
LightHouse
Avec une simulation
- DevTools
2. Comment mesurer les web vitals ?
- DevTools
- Sur un outil de CI/CD avec ligthouse-ci
Avec une simulation
2. Comment mesurer les web vitals ?
- DevTools
- Sur un outil de CI/CD avec ligthouse-ci
Avec une simulation
En conditions réelles
- librairie js web-vitals
import { getCLS, getFID, getLCP } from 'web-vitals';
getCLS(console.log);
getFID(console.log);
getLCP(console.log);
2. Comment mesurer les web vitals ?
2. Comment mesurer les web vitals ?
2. Comment mesurer les web vitals ?
2. Comment mesurer les web vitals ?
2. Comment mesurer les web vitals ?
1. Du vocabulaire
✔️
✔️
Comment on les améliore ?
❓
2. Mesurer les web vitals
✔️
✔️
T = 0
T = beaucoup de temps après T0
html
css
js
png / jpg
temps (ms)
FCP
réseau
CPU
TTI
}
exécution
3. Améliorer les web vitals
3. Améliorer les web vitals
WebP
AVIF
JPEG XL
<picture>
<source srcset="image.avif" type="image/avif" />
<source srcset="image.jxl" type="image/jxl" />
<source srcset="image.webp" type="image/webp" />
<img src="image.jpg" alt="An amazing image" />
</picture>
-60%
3. Améliorer les web vitals
214 Mo
1.49 Mo
3. Améliorer les web vitals
webpack-bundle-analyzer
3. Améliorer les web vitals
//fonction qui retourne le double d'un nombre
function double(nombre) {
return nombre * 2;
}
Minification
function d(n){return n*2}
98 caractères VS 25 caractères
3. Améliorer les web vitals
module.exports = {
// ...
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
}
}
webpack.config.js
1.49 Mo -> 617 ko
-59%
3. Améliorer les web vitals
bundlephobia
3. Améliorer les web vitals
1.49 Mo -> 376 ko
-75%
webpack-bundle-analyzer
import _ from 'lodash'
3. Améliorer les web vitals
Tree shaking 🌳
{
"name": "Amabay",
...
"sideEffects": [
"**/*.css",
"**/*.scss",
"src/config/config-with-side-effects.js"
]
}
package.json
comportement global ~= polyfill, css, ...
3. Améliorer les web vitals
module.exports = {
// ...
optimization: {
usedExports: true,
sideEffects: true,
}
}
webpack.config.js
376 ko -> 320 ko
-15%
3. Améliorer les web vitals
Tree shaking
{
// ...
plugins: [
// ...
new PurgecssPlugin({
paths: glob.sync(`${path.join(__dirname, './src')}/**/*`, { nodir: true }),
}),
new OptimizeCssAssetsPlugin(),
]
}
9.88 ko -> 7.88 ko
-20%
Minification
PurgeCssPlugin
OptimizeCssAssetsPlugin
webpack.config.js
3. Améliorer les web vitals
Gzip
brotli
webpack.config.js
{
// ...
plugins: [
// ...
new CompressionPlugin({
filename: '[path].gz',
algorithm: 'gzip',
test: /\.(js|css|html)$/,
minRatio: 0.8,
}),
new CompressionPlugin({
filename: '[path].br',
algorithm: 'brotliCompress',
test: /\.(js|css|html)$/,
compressionOptions: { level: 11 },
minRatio: 0.8,
}),
]
}
-55%
-60%
3. Améliorer les web vitals
1.94 Mo
599 ko
~70%
FCP
9.3s -> 3.3s
LCP
11.5s -> 6.4s
3. Améliorer les web vitals
1. Du vocabulaire
✔️
✔️
2. Mesurer les web vitals
✔️
✔️
3. Améliorer les web vitals
✔️
✔️
✔️
✔️
T = 0
html
css
js
png / jpg
temps (ms)
FCP
réseau
CPU
TTI
}
exécution
T = un peu moins de temps après
3. Améliorer les web vitals
temps CPU
3. Améliorer les web vitals
3. Améliorer les web vitals
App.jsx
import React from 'react';
import Navbar from '../Navbar';
import Shelf from '../Shelf';
import Filter from '../Shelf/Filter';
import FloatCart from '../FloatCart';
const App = () => (
<>
<Navbar />
<main>
<Filter />
<Shelf />
</main>
<FloatCart />
<>
);
export default App;
const Navbar = import('../Navbar');
const Shelf = import('../Shelf');
const Filter = import('../Shelf/Filter');
const FloatCart = import('../FloatCart');
3. Améliorer les web vitals
App.jsx
import React, { Suspense } from 'react';
import Loader from '../Loader';
const Navbar = React.lazy(() => import('../Navbar'));
const Shelf = React.lazy(() => import('../Shelf'));
const Filter = React.lazy(() => import('../Filter'));
const FloatCart = React.lazy(() => import('../FloatCart'));
const App = () => (
<React.Fragment>
<Suspense fallback={<Loader/>}>
<Navbar />
</Suspense>
<main>
<Suspense fallback={<Loader/>}>
<Filter />
</Suspense>
<Suspense fallback={<Loader/>}>
<Shelf />
</Suspense>
</main>
<Suspense fallback={<Loader/>}>
<FloatCart />
</Suspense>
</React.Fragment>
);
3. Améliorer les web vitals
3. Améliorer les web vitals
<link rel=”preload”>
<link rel=”prefetch”>
3. Améliorer les web vitals
App.jsx
const Navbar = React.lazy(() => import(/* webpackChunkName: 'navbar' */ '../Navbar'));
const Shelf = React.lazy(() => import(/* webpackChunkName: 'shelf' */ '../Shelf'));
const Filter = React.lazy(() => import(/* webpackChunkName: 'filter' */ '../Shelf/Filter'));
const FloatCart = React.lazy(() => import(/* webpackChunkName: 'float-cart' */'../FloatCart'));
// ...
plugins: [
// ...
new PreloadPlugin({
rel: 'preload',
include: ['navbar', 'shelf']
)},
new PreloadPlugin({
rel: 'prefetch',
include: ['filter', 'float-cart']
)},
],
webpack.config.js
3. Améliorer les web vitals
3. Améliorer les web vitals
// ...
plugins: [
// ...
new HtmlWebpackPlugin({
// ...
preconnect: ['http://localhost:8081']
}),
new HtmlWebpackPreconnectPlugin(),
],
webpack.config.js
3. Améliorer les web vitals
// ...
plugins: [
// ...
new HtmlWebpackPlugin(),
new HtmlInlineScriptPlugin([
/runtime~.+[.]js$/,
/app~.+[.]js$/
]),
],
webpack.config.js
3. Améliorer les web vitals
3. Améliorer les web vitals
3. Améliorer les web vitals
1. Du vocabulaire
✔️
✔️
2. Mesurer les web vitals
✔️
✔️
3. Améliorer les web vitals
✔️
✔️
✔️
✔️
✔️
✔️
✔️
✔️
stratégie de mise en cache (assets, app shell...)
lazy loading des images
HTTP2
cache réponses API
SSR
Conclusion
Conclusion
🙏
#DevoxxFR