👣: there will be some things I won't cover
When upgrading an entire app...
Measure, Optimize, Monitor
performance
load time
javascript
images
🔃 Fast load
🐘 Small footprint
#1
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = () => ({
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'index.html'),
filename: 'index.html',
inject: "body",
minify: {
html5: true,
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true,
minifyURLs: false,
removeComments: true,
}
})
]
});
#2
⚪ one file per component/page
⚪ the twice rule!
Don't wanna have 1 gigantic CSS for the whole app...
#3
Responsive
Lazy Load
NextGen Formats
<picture>
<source
srcset="share_high.jpg"
type="image/jpeg" media="(min-width: 1000px)">
<source
srcset="share_low.jpg"
type="image/jpeg" media="(min-width: 600px)">
<img src="share_very_low".jpg alt="people talking">
</picture>
<picture>
<source
class="lazyload"
data-srcset="share_high.jpg"
type="image/jpeg" media="(min-width: 1000px)">
<source
class="lazyload"
data-srcset="share_low.jpg"
type="image/jpeg" media="(min-width: 600px)">
<img
class="lazyload"
data-src="share_very_low".jpg alt="people talking">
</picture>
import "lazysizes";
<picture>
<source
class="lazyload"
data-srcset="share_high.jpg"
type="image/jpeg" media="(min-width: 1000px)">
<source
class="lazyload"
data-srcset="share_low.jpg"
type="image/jpeg" media="(min-width: 600px)">
<noscript>
<img src="share_med.jpg" alt="people talking">
</noscript>
<img
class="lazyload"
data-src="share_very_low".jpg alt="people talking">
</picture>
<picture>
<source
class="lazyload"
data-srcset="share.webp"
type="image/webp">
<noscritp>
<!-- ... -->
</noscript>
<img
class="lazyload"
data-src="share".jpg alt="people talking">
</picture>
const WebpImagesPlugin = require('imagemin-webp-webpack-plugin')
module.exports = () => ({
plugins: [new WebpImagesPlugin ()]
});
#4
<head>
<link
href="https://fonts.googleapis.com/css?family=Comfortaa:400,700"
rel="stylesheet">
<link
href="https://fonts.googleapis.com/css?family=Lato:400,700"
rel="stylesheet">
<link href="style.css" href="stylesheet">
</head>
body {
font-family: 'Lato', sans-serif;
}
GET: index.html
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url(https://fonts.gstatic.com/s/lato/v14/S6uyw4BMUTPHjx4wXg.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
❗ Oh! The body's using the font!
GET: https://fonts.googleapis.com/...
GET: style.css
GET: [].woff2
<link
rel="preload"
as="font"
href="/dist/assets/fonts/comfortaa-v12-latin-regular.woff2"
type="font/woff2"
crossorigin="anonymous" />
#5
gzip
JS code
"archived"
compress
===
const express = require('express');
const compression = require('compression');
const app = express();
app.use(compression());
app.use('/dist', express.static(`${__dirname}/dist`, {
maxAge: 31536000
}));
performance
load time
javascript
images
#6
render() {
return (
<div className="app">
<Switch>
<Route exact path="/" component={LandingPage} />
<Route path="/trials" component= {TrialsPage} />
<Route exact path="/home" component={HomePage} />
<Route path="/team/:adminUsername/:teamId" component={TeamPage} />
<Route exact path="/exercise/new" component={NewExercisePage} />
<Route exact path="/join/:joinHash" component={JoinPage} />
<Route path="/login" component={LoginPage} />
<Route path="/privacy" component= {PrivacyPage} />
<Route path="/press-kit" component= {PressKitPage} />
<Route component={NotFound} />
</Switch>
</div>
);
}
<Route exact path="/" component={LazyLanding} />
import React from 'react';
import Loadable from 'react-loadable';
import RouterLoading from '../RouterLoading.component';
const LazyLandingPage = Loadable({
loader: () => import('./Landing.page'),
modules: ['./Landing.page'],
webpack: () => [require.resolveWeak('./Landing.page')],
loading: RouterLoading
});
export default (props) => <LazyLandingPage {...props} />;
#7
How about loading it just when I need it?
AKA: on button click
onClick() {
import('../Swal.service').then(SwalService => {
/* Use it */
});
}
#8
#9
performance
load time
javascript
images
#10
#10
self.addEventListener('fetch', function onFetch(event) {
if (event.request.url.indexOf(location.origin) === 0) {
event.respondWith(cacheOrNetwork(event));
}
});
#11
{
"bundlesize": [{
"path": "./dist/**/*.css",
"compression": "none",
"maxSize": "50 kB"
},
{
"path": "./dist/**/!(*.worker).js",
"compression": "none",
"maxSize": "300 kB"
},
{
"path": "./dist/**/*_high.jpg",
"maxSize": "800 kB"
},
{
"path": "./dist/**/*_med.jpg",
"maxSize": "200 kB"
},
{
"path": "./dist/**/*_low.jpg",
"maxSize": "100 kB"
},
{
"path": "./dist/**/!(*_high|*_med|*_low|*_seo*).jpg",
"compression": "none",
"maxSize": "100 kB"
}],
"scripts": {
"perf-test": "bundlesize"
}
}
$ lighthouse http://localhost:1234
--output json --output-path ./audit.json
but now what...?