-
Recording performance optimization videos for presentations and demos
tl;dr: Use ScreenToGif, Shotcut, and FFmpeg to record load times of different treatments and show them side by side in one video.
-
onerror for detecting load failures
tl;dr: Use the
onerror
event to detectimg
,input
(oftype="image"
),object
,link
, andscript
load failures. -
Less is more: counting lines of code
tl;dr: If we think of software engineering as writing code, then refactoring and removing code must be an art. This is particularly meaningful when shipping JavaScript code that’s based on a client-side rendering framework.
-
Color-coded "status architecture" diagrams
tl;dr: “Status architecture” is a term I made up to represent a color-coded architecture diagram that depicts not only how the system works, but also where we stand when it comes to getting the project released to production. I found it’s helpful for others to quickly understand bottlenecks just by glancing over such “status architecture” diagrams.
-
new Error().stack for tracing setTimeout calls
tl;dr: By using
setInterval
or by recursively callingsetTimeout
, your code inadvertently slows down performance. Prefer using events to polling for a change in property values. -
monitor utility
tl;dr:
monitor(fetch)
can be used in the context of DevTools to print all fetch requests. More so,monitor(setInterval)
andmonitor(setTimeout)
can be used to detect symptoms of bad coding. -
debug utility
tl;dr:
debug(fetch)
can be used in the context of DevTools to break on any outgoing fetch operation. There are more console utilities that can be used to ease debugging. -
Webpack bundle size debugging
tl;dr: A tiny script to list all files that are bundled together by Webpack. It’s useful to track unexpected external dependencies, internal libraries, SVG icons, or just plain JavaScript that’s not tree-shaken away.
-
getEventListeners utility
tl;dr: Use
getEventListeners
in Chromium/Safari DevTools to get an idea of what’s being run “concurrently” and vying for resources. Note thatgetEventListeners
only exists in the context of DevTools. -
OPTIONS preflight caching
tl;dr: Cross-Origin Resource Sharing (CORS), a good practice enforced by browsers for security purposes is a performance slowdown. Thus, the next best thing you can do starting with the 2nd request, is to cache your OPTIONS preflight responses, but there’s a catch.
-
adoptedStyleSheets as a performance optimization
tl;dr: Use
document.adoptedStyleSheets
to attach one constructable stylesheet to many shadow roots. This offloads style changes to the browser and updates all web components that have adopted these style sheets. Otherwise, you’ll have to use JavaScript to “manually” update each shadow root which means it’s likely going to be slower. -
Server-Timing HTTP header
tl;dr: Use
Server-Timing
HTTP header to help debug internal latencies. While this is useful for debugging, it does potentially expose how your services are connected to each other. Even so, the debugging benefits outway the privacy risk. -
JPEG minification with mozjpeg
tl;dr: Use
mozjpeg
to minify JPEGs. -
PNG minification with pngquant
tl;dr: Use
pngquant
to minify PNGs. -
GIF minification with gifsicle
tl;dr: Use
gifsicle
to minify GIFs. -
preload relationship
tl;dr: Use
<link rel="preload" href="/assets/atkinson-hyperlegible-regular-102a.woff2" />
to tell the browser it needs to schedule the asset to be downloaded and cached with higher priority. -
sticky position
tl;dr: Use
position: sticky;
to create parallax effects. Avoid any JavaScript as much as possible and use native CSS to handle the logic because it’s much more performant. -
bind memoization
tl;dr: Calling
bind
on a function is expensive because each call creates a net new function. Memoize bindings outside of loops and just call the bound functions inside the loops. -
preconnect relationship
tl;dr: Use
<link rel="preconnect" href="https://api.example.com" />
if you know your website will make requests to your API, thumbnail, CDN endpoints etc. -
merge chained filters
tl;dr: Refactor sample code like
[].filter((v) => v >= 0.4).filter((v) => v <= 0.6)
to[].filter((v) => v >= 0.4 && v <= 0.6)
. This way, code will iterate on the array just once, rather than n times (once for eachfilter
call). -
ApacheBench
tl;dr: If you need a quick way to test any API or server-side rendered (SSR) web page, use
ab -c 10 -n 100 "https://example.com/"
which says issue 10 concurrent out of 100 total requsts. This Apache benchmarking tools then displays performance statistics. -
HTTP/3
tl;dr: HTTP/3 is UDP-based, rather than TCP-based, thus connections are established faster. It’s based on Google’s QUIC protocol. Use HTTP/3 if available.
-
will-change
tl;dr: Use the
will-change
CSS property to hint the rendering engine to optimize animations. Avoid thetransform: translate3d(0, 0, 0);
trick. -
addEventListener + removeEventListener
tl;dr: Avoid memory leaks by ensuring that if you register a callback to
addEventListener
you also unregister it withremoveEventListener
later on. -
structuredClone instead of JSON.parse + JSON.stringify
tl;dr: To deep clone objects, Use
structuredClone(value)
rather than theJSON.parse(JSON.stringify(value))
trick. Also, avoid Lodash’s_.cloneDeep(value)
due to import cost. -
requestAnimationFrame + setTimeout
tl;dr: This is how you correctly measure performance after style, layout, and paint operations.
-
V8 flags
tl;dr: A printout of all Chromium V8 flags. Some are useful for debugging.
-
HTTP/2
tl;dr: Avoid HTTP/1.1 because browsers limit the number of concurrent requests going to HTTP/1.1 origins. Use HTTP/2.
-
performance
tl;dr: Avoid using
Date
to measure durations. Use theperformance
interface to measure durations because of its high precision. -
Intl
tl;dr: Use
Intl
to compute relative dates, rather than rely on Luxon or Moment which are huge size-wise. -
lazy loading
tl;dr: Use
loading="lazy"
to defer loading images that are off-screen until the user scrolls near them. -
SVG minification with svgo
tl;dr: Use
svgo
to minify SVGs. -
Brotli compression
tl;dr: Compress assets such as JavaScript and CSS using Brotli rather than gzip.