Jonathan Hervieux @djow__
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 ?
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
(Real User Monitoring)
- 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 ?
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
3. Améliorer les web vitals
<picture>
<source srcset="image.avif" type="image/avif" />
<source srcset="image.webp" type="image/webp" />
<source srcset="image.jpeg" type="image/jpeg" />
<img src="image.jpeg" alt="Image" />
</picture>
Tag picture
3. Améliorer les web vitals
<picture>
<source srcset="image.jpeg?as=avif&width=800" type="image/avif" />
<source srcset="image.jpeg?as=webp&width=800" type="image/webp" />
<source srcset="image.jpeg?width=800" type="image/jpeg" />
<img src="image.jpeg?width=200" alt="Image" />
</picture>
Exemple avec Parcel
3. Améliorer les web vitals
webpack-bundle-analyzer
bundlephobia
3. Améliorer les web vitals
Minification
Tree shaking
Tree shaking
{
// ...
webpack: {
plugins: {
add: [
// ...
new PurgecssPlugin({
paths: glob.sync(`${path.join(__dirname, './src')}/**/*`, { nodir: true }),
}),
]
}
}
}
Minification
PurgeCssPlugin
CssMinimizerWebpackPlugin
craco.config.js
3. Améliorer les web vitals
1. Du vocabulaire
✔️
✔️
2. Mesurer les web vitals
✔️
✔️
3. Améliorer les web vitals
✔️
✔️
✔️
3. Améliorer les web vitals
Gzip
brotli
-55%
-60%
3. Améliorer les web vitals
craco.config.js
{
// ...
webpack: {
plugins: {
add: [
// ...
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,
}),
]
}
}
}
3. Améliorer les web vitals
{
"compressors": {
"*.{html,css,js,svg,map}": [
"...",
"@parcel/compressor-gzip",
"@parcel/compressor-brotli"
]
}
}
.parcelrc
import viteCompression from 'vite-plugin-compression';
export default () => {
return {
plugins: [viteCompression()],
};
};
vite.config.js
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
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
<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']
)},
],
craco.config.js
3. Améliorer les web vitals
navbar.a4dee578.chunk.js
3. Améliorer les web vitals
{
//...
webpack: {
plugins: {
add: [
new HtmlWebpackPreconnectPlugin(),
],
},
configure: (webpackConfig) => {
const { isFound, match } = getPlugin(webpackConfig, pluginByName("HtmlWebpackPlugin"));
if (isFound) {
match.userOptions.preconnect = ["http://localhost:8081"];
}
return webpackConfig;
},
},
};
craco.config.js
3. Améliorer les web vitals
<!doctype html>
<html lang="fr">
<head>
<title>Mon App</title>
<script defer="defer" src="/static/js/main.eabb2562.js"></script>
<link href="/static/css/main.00b42aeb.css" rel="stylesheet">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
index.html
3. Améliorer les web vitals
temps (ms)
index.html
main.js
main.css
1.chunk.js
2.chunk.js
3.chunk.js
// ...
plugins: [
// ...
new HtmlInlineScriptPlugin([
/main~.+[.]js$/,
]),
],
craco.config.js
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
SSR
profiling
🙏