Empowering Performance Culture
,
&nsbp;
Hearst is a media company with more than 360 businesses.
Its major interests include magazines, TV networks, newspapers and more.
Elle Logo
const perfume = new Perfume({
firstPaint: true,
firstContentfulPaint: true,
firstInputDelay: true,
googleAnalytics: {
enable: true,
timingVar: "userId"
}
})
// Perfume.js: First Paint 1482.00 ms
// Perfume.js: First Contentful Paint 2029.00 ms
// Perfume.js: First Input Delay 3.20 ms
Graph
Graph
200 KB
200 KB
// feed container
const feed = document.querySelector('.feed');
// get the closest element to the middle of the feed
const middleish = feed.children[Math.floor(feed.childElementCount / 2 )];
// create an IntersectionObserver
const io = new IntersectionObserver((entries) => {
entries.forEach(async (entry) => {
if (!entry.isIntersecting) return;
io.disconnect();
// import the module
const infiniteLoad = await import('app/modules/infinite-load')
infiniteLoad.setup(feed);
})
})
// observe the middle element
io.observe(middleish);
<a class="nav-search-button" href="#searchoverlay" title="Search">
<span class="icon icon-search"></span>
</a>
<section id=#searchoverlay">
<!-- modal content !-->
</section>
#searchoverlay {
position: fixed;
width: 100vw;
height: 100vh;
transition: opacity 0.3s ease-in;
z-index: -1;
}
#searchoverlay:target {
z-index: 0;
opacity: 1;
}
<details class="search">
<summary>Search</summary>
<section>
THIS IS A MODAL
</section>
</details>
details summary::-webkit-details-marker {
display:none;
}
details summary {
cursor: pointer;
outline: none !important;
display: inline-block;
/* etc */
}
details[open] > summary::before {
position: fixed;
cursor: default;
content: " ";
z-index: 99;
background: rgba(27,31,35,0.5);
}
details > section {
left: 50%;
margin: 10vh auto;
max-height: 80vh;
max-width: 90vw;
position: fixed;
top: 0;
transform: translateX(-50%);
}
// main.js
import * as Comlink from "comlink";
const worker = new Worker("worker.js");
// `app` lives in the worker
const app = await Comlink.wrap(worker);
const result = await app.doSomething();
console.log(result);
// worker.js
import * as Comlink from "comlink";
const app = {
doSomething() {
// perform operations
return result;
}
}
Comlink.expose(app);
<head>
<!-- worker-dom library -->
<script src="worker-dom.js" defer></script>
</head>
<body>
<!-- src is the path to the file -->
<section src="app.js" class="app-script">
<p>Hello World!</p>
<input/>
</section>
<script>
document.addEventListener(
'DOMContentLoaded', function() {
const appScript = document.querySelector('.app-script');
// MainThread is defined by worker-dom.js
// worker.js is also part of the library
MainThread.upgradeElement(appScript, './worker.js');
}, false);
</script>
</body>
// app.js
const p = document.createElement('p');
const text = document.createTextNode('Hello World!');
const input = document.createElement('input');
p.appendChild(text);
document.body.appendChild(p);
document.body.appendChild(input);
function toggle() {
p.style.color = p.style.color === "green" ? "red" : "green";
}
input.addEventListener('input', event => {
if (event.currentTarget.value === 'change') {
toggle();
}
}, false);
Loads page with ?third-parties
Tag manager loads all scripts
Collect all third-party files and store them
In-memory DB
Store the links
to the URL
On content invalidation,
or at a scheduled time
trigger the function
// module-a.js
requestAnimationFrame(() => {
const { right, bottom } = el.getBoundingClientRect();
});
// module-b.js
requestAnimationFrame(() => {
el.classList.add('change-size'); 😱
});
const io = new IntersectionObserver((entries) => {
entries.forEach(entry => {
// entry.boundingClientRect
// entry.intersectionRatio
// entry.intersectionRect
// entry.isIntersecting
// entry.rootBounds
// entry.target
// entry.time
});
});
// observe the element
io.observe(el);
const getBoundingClientRect = el =>
new Promise((resolve) => {
const io = new IntersectionObserver((entries) => {
resolve(entries.shift().boundingClientRect);
io.disconnect();
});
io.observe(el);
});
const header = document.querySelector('.header');
// ❌ const { top, left, right, bottom } = header.getBoundingClientRect();
✅ const { left, top, right, bottom } = await getBoundingClientRect(header);
This is where Performance mostly happens.
This is where we think
it should happen.
This is where it should happen.
Github Action - Coming soon...
Collect all open PRs daily
with labels E.g
"Ready to Merge"
Open PR
and assign users
from a config value
{
"baseUrl": "https://example.com",
"ci": "[ci]",
"type": "[type]",
"settings": {
"categories": {
"performance": 70,
"accessibility": 70,
"best-practices": 70,
"pwa": 70
},
"budgets": [
{
"resourceSizes": [
{
"resourceType": "script",
"budget": 300
}
],
"resourceCounts": [
{
"resourceType": "third-party",
"budget": 50
},
]
}
]
},
"routes": [
"/",
{ "url": "/articles", "settings": {...} }
]
}
{
"baseUrl": "https://example.com",
"ci": "[ci]",
"type": "[type]",
"settings": {
"categories": {
"pwa": {
"target": 90,
"threshold": 40,
"warning": 10
}
}
},
"sharedSettings": {
"galleries": {
"extends": true,
"categories": {
"pwa": {
"threshold": 20
}
},
"lighthouse": {
"options": {
"emulatedFormFactor": "desktop",
"extraHeaders": {
"X-CUSTOM-HEADER": "gallery-header"
}
}
}
}
},
"routes": [
"/article/1/",
{
"url": "gallery/1",
"settings": "galleries"
},
{
"url": "gallery/2",
"settings": {
"extends": "galleries",
"categories": {
"pwa": {
"target": 80
}
}
}
}
]
}