Performance - Part one
how do we go from this:
or this?
To this?
or even this?
optimization checklist
- Optimize images
- Eliminate render-blocking JavaScript and CSS in above-the-fold content
- Leverage browser caching
- Minify JavaScript
- Minify CSS
- Minify HTML
- Enable compression
optimize images
- Use the right compression
- Responsive images: srcset, x and w descriptors
- Picture-element
- Verify which image is served from DevTools
eliminate render-blocking js + CSS
- Use a small inline style-block for above-the-fold content if possible OR use a small, initial CSS file
- Load scripts just before </body>
- Load with async or defer when possible
- Load CSS and webfonts from script
<style>
body {
font-family: sans-serif;
}
.g20, .g25, .g33, .g50, .g66, .g75, .g100 {
float: left;
display: flex;
}
.g20 { width: 50%; }
.g25 { width: 50% }
.g33 { width: 100% }
.g50 { width: 100%; }
.g66 { width: 66.666666%; }
.g75 { width: 75%; }
.g100 { width: 100%; }
@media only screen and (min-width:769px){
.g20{ width: 20%; }
.g25 { width: 25%; }
.g33 { width: 33.333333%; }
.g50 { width: 50%; }
}
.inner {
display: flex;
flex-flow: row wrap;
max-width: 1024px;
margin: 0 auto;
padding: 0 10px;
}
</style>
<script async>
function loadCSS(sURL) {
var
oLink = document.createElement("link");
oLink.setAttribute("rel", "stylesheet");
oLink.setAttribute("href", sURL);
oLink.setAttribute("type", "text/css");
document.body.appendChild(oLink);
}
loadCSS("/assets/css/styles.css");
loadCSS("//fonts.googleapis.com/css?family=Montserrat:700|Oswald:400,300,700|Questrial|Roboto:300,400");
</script>
leverage browser caching
- Set Cache-Control headers
- Set ETags (Validaton tokens)
minify javascript
- Use uglify or other minifier from Gulp
minify css
- Set outputStyle="compressed" in gulp-sass
minify html
- If serving a static site, do it from Gulp
- Sitecore and epiServer can do it ... but it might not be worth it ...
Enable compression
- Gzip everything above a specified threshold, could be 1024 kb
- DON'T gzip files which are already compressed, they will end up bigger than the original files
- If using a CDN, pre-gzip and set correct mime-type and Content-Encoding-header to "gzip"
- If using IIS, add SVG mime-type
example: deploy to s3 from gulp
function gzipS3(sPrefix, sPath) {
return gulp.src(sPath)
.pipe(gzip(GZIP_OPTIONS))
.pipe(rename(function(filePath) {
filePath.dirname = path.join(sPrefix, filePath.dirname);
}))
.pipe(s3(AWS_SETTINGS, AWS_OPTIONS))
.pipe(debug())
.pipe(gulp.dest("./gzip/"));
}
caching and offline
a short intro to pwa's
Psst! Go to the "Application"-tab in DevTools
the manifest
{
"short_name": "Blocks!",
"name": "Blocks! UI Elements",
"description": "A collection of UI elements and patterns",
"icons": [
{
"src": "/assets/favicon/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/assets/favicon/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/",
"dir": "ltr",
"lang": "en-US",
"display": "standalone",
"orientation": "any",
"background_color": "white",
"theme_color": "cornflowerblue"
}
the serviceworker
var CACHE_NAME = "blocks-cache-v1";
var CACHED_URLS = [
"/offline.html",
"/assets/css/styles.css",
"/assets/favicon/favicon.ico"
];
self.addEventListener("install", function(event) {
event.waitUntil(
caches.open(CACHE_NAME).then(function(cache) {
return cache.addAll(CACHED_URLS);
})
);
});
self.addEventListener("fetch", function(event) {
event.respondWith(
fetch(event.request).catch(function() {
return caches.match(event.request).then(function(response) {
if (response) {
return response;
} else if (event.request.headers.get("accept").includes("text/html")) {
return caches.match("/offline.html");
}
...
USING SW-precache
gulp.task("sw", function(callback) {
swPrecache.write("./serviceworker.js", {
staticFileGlobs: [
"*.{html,js}",
"files.json",
"assets/**/*.*",
"feature/**/*"
]
}, callback);
});
indexeddb
function getDB() {
if (!oDB) {
oDB = new Promise(function (resolve, reject) {
var oRequest = window.indexedDB.open(oSettings.DB, oSettings.Version);
oRequest.onerror = function () {
reject(oRequest.error);
};
oRequest.onupgradeneeded = function () {
var oStore = oRequest.result.createObjectStore(oSettings.Store);
oStore.createIndex("timestamp", "timestamp");
};
oRequest.onsuccess = function () {
resolve(oRequest.result);
...
fine-tuning
adding resource hints
<link rel="dns-prefetch" href="//example.com">
<link rel="preconnect" href="//example.com">
<link rel="prefetch" href="image.png">
<link rel="prerender" href="//example.com">
<link rel="preload" href="image.png">
minifying html?
probably not worth it
29kb HTML ~ 2.42kb gzipped
27kb HTML ~ 2.26kb gzipped
http2, SERVICEWORKER
advice editors ... again
(10 mb gif not allowed)
Performance - Part One
By Mads Stoumann
Performance - Part One
- 47