HTML Optimization for
Web Perfomance
Frontend Conference Fukuoka 2019
Shogo SENSUI (@1000ch)
Shogo SENSUI (@1000ch)
Why HTML Optimization?
HTML is the first step of rendering a page
The origin of
subresources
Loading order affects rendering speed directly
Independent of
web page type
Regardless of dynamic web application or not
Easy to optimize
relatively
Mostly completing in HTML
3 steps for HTML Optimization
Understanding
Critical Rendering Path
Browser Loading Process
Construct
DOM Tree
Construct
CSSOM Tree
Create
Render Tree
Layout & Paint
Execute
JavaScript
1st step. Load HTML
<html>
<head>
<meta charset="utf-8">
<title>Basic HTML structure</title>
<link rel="stylesheet" href="foo.css">
<link rel="stylesheet" href="bar.css">
</head>
<body>
<img src="hero.jpg">
<script src="app.js"></script>
<script defer src="3rd-party.js"></script>
</body>
</html>
2nd step. Load subresources
<html>
<head>
<meta charset="utf-8">
<title>Basic HTML structure</title>
<link rel="stylesheet" href="foo.css">
<link rel="stylesheet" href="bar.css">
</head>
<body>
<img src="hero.jpg">
<script src="app.js"></script>
<script defer src="3rd-party.js"></script>
</body>
</html>
3rd step. Render pages
without CSSOM
with CSSOM
Measuring
Performance Metrics
Wait, Load and DOMContentLoaded events?
Which experience would you prefer?
Time to Interactive Demo (Airbnb mobile web)
User Centric Performance Metrics
const po = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
// `entry` is a PerformanceEntry instance.
console.log(entry.entryType);
console.log(entry.startTime);
console.log(entry.duration);
}
});
// Start observing the entry types you care about.
po.observe({
entryTypes: ['resource', 'paint']
});
To measure FP, FCP, LCP:
const observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
ga('send', 'event', {
eventCategory: 'Performance Metrics',
eventAction: entry.name,
eventValue: entry.startTime + entry.duration,
nonInteraction: true
});
}
});
// Start observing the entry types, FP, FCP, LCP.
observer.observe({
entryTypes: ['paint', 'largest-contentful-paint']
});
To measure LongTasks:
const observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
ga('send', 'event', {
eventCategory: 'Performance Metrics',
eventAction: 'longtask',
eventValue: Math.round(entry.startTime + entry.duration),
eventLabel: JSON.stringify(entry.attribution),
});
}
});
// Start observing the entry types, Long Task.
observer.observe({
entryTypes: ['longtask']
});
Performance Audit Tools
How to optimize HTML?
All (sub-)resources should be minified
Optimize CSS Loading
Optimize JavaScript Loading
Basic HTML structure will be...
<html>
<head>
<meta charset="utf-8">
<title>Basic HTML structure</title>
<link rel="stylesheet" href="foo.css">
<link rel="stylesheet" href="bar.css">
</head>
<body>
<!-- ... -->
<script src="app.js"></script>
<script defer src="3rd-party.js"></script>
</body>
</html>
Preload subresources
<link rel="preload" href="audio.mp3" as="media">
<link rel="preload" href="app.css" as="style">
<link rel="preload" href="app.js" as="script">
<link rel="preload" href="hero.jpg" as="image">
Preload for module scripts
<head>
<link rel="modulepreload" href="app.mjs">
</head>
<!-- ... -->
<script type="module" src="app.mjs"></script>
Native lazy-loading for <img> and <iframe>
<img src="image.png" loading="lazy" alt="…">
<iframe src="https://example.com" loading="lazy"></iframe>
Priority Hints for subresources
<!-- An image the browser assigns "High" priority, but we don't actually want that. -->
<img src="in_viewport_but_not_important.svg" importance="low" alt="...">
<!-- We want to initiate an early fetch for a resource, but also deprioritize it -->
<link rel="preload" href="/js/script.js" as="script" importance="low">
<script src="/js/app.js" defer importance="high"></script>
Resource Hints
<link rel="dns-prefetch" href="//example.com">
<link rel="preconnect" href="//example.com">
<link rel="preconnect" href="//cdn.example.com" crossorigin>
<link rel="prefetch" href="next-page.html" as="document">
<link rel="prefetch" href="lib.js" as="script">
<link rel="prerender" href="next-page.html">
Conclusion
Conclusion
Further information?
Thank for listening 🙌
Ask me anything ❤️ by @1000ch