HNHacker News
TopNewBestAskShowJobs

iamakulov

251 karma · joined November 23, 2016

React / web performance engineer. Currently, a Staff Performance Engineer at Framer. Previously, a solo web perf consultant (Google, Restream, Toggl, etc). https://twitter.com/iamakulov
submissionscomments
iamakulov··on Interaction to Next Paint (INP)
> It also seems to be a metric that is very easily gamed.

Fun fact: the current JS-specific metric (which is being fazed out) is First Input Delay, and it was explicitly designed to avoid this gaming:

> FID only measures the "delay" in event processing. It does not measure the event processing time itself nor the time it takes the browser to update the UI after running event handlers. While this time does affect the user experience, including it as part of FID would incentivize developers to respond to events asynchronously—which would improve the metric but likely make the experience worse. > - https://web.dev/fid/

I wonder why they decided to reconsider this trade-off when designing INP.

iamakulov··on Interaction to Next Paint (INP)
Isn’t that tweet talking about 2.4s for Largest Contentful Paint? It mentions 0.9 for FCP being fast, which I agree is pretty reasonable.
iamakulov··on Interaction to Next Paint (INP)
This is correct (source: working in web perf for 5 years).

INP is the time between you click/press a key/etc and the moment the next paint happens. It’s only measured for on-page interactions, not for navigations.

It’s basically like http://danluu.com/input-lag/ but as a web metric.

iamakulov··on CommonJS is not going away
Bun’s blog post doesn’t explicitly mention Deno’s “CommonJS is hurting JavaScript” post, but it feels like a response to that.

Deno discussion: https://news.ycombinator.com/item?id=36537533

iamakulov··on macOS 14 will support JPEG XL
Relevant thread, for those who’re curious: https://bugs.chromium.org/p/chromium/issues/detail?id=117805...
iamakulov··on macOS 14 will support JPEG XL
Not really.

AFAIK (correct me if I’m wrong!) first-party and third-party codecs in media players are kinda equal: you load a file, and the media player picks which codec to delegate that file to. You can’t do that in with a Chrome extension – the extensions can manipulate HTML and run custom JS, but that’s more or less it (plus some basic browser-level stuff like work with tabs and intercept network requests).

This doesn’t mean an extension isn’t possible at all – eg there’s https://github.com/zamfofex/jxl-crx/ that detects JXL images and decodes them with JS – but that’s slower.

Plus the bigger issue is adoption. You want all users to get your JPEG XL images, not just the 0.1% of users that installed the extension.

iamakulov··on Case study: making a React/Redux app interaction ~4× faster
Hey HackerNews!

This fall, I was lucky to help Causal (a web spreadsheet for forecasting) with speeding up their frontend app. Here are some of my favorite findings:

- Turns out when React DevTools tell you “the component rerenderd because hook no. 2 changed”, it doesn’t mean that it’s hook no. 2 that actually changed! That’s because a) `useContext` hooks aren’t counted, b) only native hooks are counted – so if you use one `useSelector`, but it has 8 native hooks inside, you’ll see something like “hook no. 7 changed”. You need to go to the Components pane and look for hook numbers there.

- Web workers are cool but hard to make use of :/ In this case, we tried moving an operation into a web worker but weren’t able to because copying data between threads took longer than the actual op. And one doc I’ve read earlier still fascinates me – in 2018, Google explored moving frameworks into web workers but stumbled upon many limitations [1].

- React (unfortunately) still causes a lot of performance issues. It’s too easy to rerender something unnecessarily; and in a large app, many cheap components easily add up into an expensive render. I’m looking forward to React Forget [2], hopefully, solving this (at least partially?)

[1] https://docs.google.com/document/d/1nu0EcVNC3jtmUVWL8Gs5eCj2... [2] https://reactjs.org/blog/2022/06/15/react-labs-what-we-have-...

iamakulov··on [dead]
Modern Yarn supports `yarn patch`: https://yarnpkg.com/cli/patch. For Yarn 1.x and npm, I’ve used https://www.npmjs.com/package/patch-package which also works well.
iamakulov··on [dead]
(Co)author here - happy to answer any questions :)

- This was a v fun (and challenging, due to Causal's scale!) project to do

- Most optimizations we’ve implemented were (very effective) one-off fixes. But we were also glad to find some rules of thumb that help to keep the app faster by default [1]

- My most interesting discovery was how ineffective Web Workers are. Causal, sometimes, has to do some expensive client-side data parsing. We tried to move data parsing to a web worker (= a separate thread) – but ended up reverting the optimization because it made the app slower. In JS, you can’t just pass a pointer to a data structure between threads; the browser has to clone the data structure [2] (with limited exceptions [3]). In our case, cloning the data between threads ended up being several times slower than parsing it in the main thread.

[1] https://www.causal.app/blog/react-perf#span-class=inline-cod...

[2] https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers...

[3] https://developer.mozilla.org/en-US/docs/Glossary/Transferab...

iamakulov··on Case study: Analyzing Notion performance (or making a React app load 30% faster)
Hey Hacker News! I’m a long-time user of Notion (an advanced note-taking app). Notion’s web app has been quite slow for me, so I decided to reverse-engineer it and see why. Here’s a case study with findings and recommendations!

TL;DR:

* Notion has a large startup time because they serve a lot of JavaScript. This JS has to be parsed, compiled, and executed – and this takes time. This is especially slow on Android phones [1].

* The obvious solution to this is code splitting. But in case of Notion, there’re a few other low-hanging fruits. For example, if you switch to CommonJS, you can (surprisingly) speed up the startup by deferring unnecessary modules [2]. Or, there’s a bunch of unnecessary libraries in the bundle (including 3 duplicates of CoreJS).

* Apart from JS execution, there’re also a few other issues. Analytics is loaded early – and it defers loading and execution of other, more important resources [3]. And page resources don’t have `Cache-Control` headers being set, which could lead to different caching behavior in different browsers.

Overall, based on my measurements and some guesses, I think Notion can cut around 30% off their initialization time – simply by tuning some configs and deferring some loading.

Would be happy to hear your feedback :)

[1] https://3perf.com/blog/notion/#cost-of-javascript

[2] https://3perf.com/blog/notion/#try-the-lazy-option-of-babels...

[3] https://3perf.com/blog/notion/#defer-third-parties

iamakulov··on 500-byte script that makes Google Fonts render faster (up to 3s in slow network)
So, a couple months ago, I discovered a way to make a text that uses Google Fonts render faster. In slow connections, that might give a boost of 1-3 seconds. Recently, I released that as a tool.

Here’re more details:

— When you use custom fonts (like Google Fonts), most modern browsers won’t render the text with that font immediately. Instead, the text will stay invisible until the font is downloaded – or until 3 seconds pass. You might’ve experienced this yourself if you have an Android phone. This is done to prevent a FOIT (flash of invisible text), but this hurts user experience.

— A typical solution for this is to add a CSS rule like font-display: swap which tells the browser to avoid waiting for the custom font. However, Google Fonts don’t support this rule, and the only remaining solution becomes to a) self-host fonts (more hassle; impossible in some environments) or b) use JS libraries like Typekit Webfont Loader (hurts the initial font load time)

— Recently, I found a solution for this. Turns out, you can fetch a Google Fonts stylesheet asynchronously, patch it to include font-display, and insert it into the page. So I composed a tool that does it! The tool generates an inline script that does the work + a few <link rel="preload/preconnect"> tags to avoid hurting the performance. The script also does some extra work to avoid unnecessary FOUTs. The total size of the generated code snippet is 550 bytes minified + gzipped.

Here’s the source code of the generated script: https://github.com/iamakulov/googlefonts-font-display-helper...

Would love your feedback on the tool :)

iamakulov··on Show HN: Make Google Fonts Render 1-3 Seconds Faster in Slow Networks
So, a few weeks ago, I discovered a way to make a text that uses Google Fonts render faster. In slow connections, that might give a boost of 1-3 seconds. Some backstory:

* When you use custom fonts (like Google Fonts), most modern browsers won’t render the text with that font immediately. Instead, the text will stay invisible until the font is downloaded – or until 3 seconds pass. You might’ve experienced this yourself (if you had an Android phone and used a slow connection once). This is done to prevent a FOIT, but this hurts user experience.

* A typical solution for this is to add a CSS rule like `font-display: swap` which tells the browser to avoid waiting for the custom font. However, Google Fonts don’t support this rule, and the only remaining solution becomes to a) self-host fonts (annoying) b) use JS libraries like Web Font Loader (hurts the initial font load time; pretty complicated for one task)

* Recently, I found a solution for this. Turns out, you can fetch a Google Fonts stylesheet asynchronously, patch it to include font-display, and insert it into the page. So I composed a project that does it! To avoid hurting the performance, the project generates an inline script and a few `<link rel="preload/preconnect">` tags. The script also does some extra work to avoid unnecessary FOUTs. The total size of the code snippet is 550 bytes minified and gzipped.

Here’s the primary source code of the script: https://github.com/iamakulov/googlefonts-font-display-helper...

Would love your feedback on the tool :)

iamakulov··on Analyzing the Walmart site performance
Hey, I’m the author or the article. Kudos for the great work, really like the new site!
iamakulov··on Web Performance 101
So, in summer, I gave an introductory talk into web performance. This is its textual version :)

The talk includes 94 slides with text about:

  — why web performance matters
  — how to optimize:
    — JS (async/defer, code splitting)
    — CSS (the critical CSS approach & tools for it)
    — HTTP/connection stuff (Gzip/Brotli, preloading, CDN)
    — Images (compressing images, webp, progressive vs baseline images)
    — Fonts (the `font-display` trick)
  — and what tools help to understand your app’s performance
Would love to hear your feedback :)
iamakulov··on Malicious crossenv package on npm
npm is working on a solution for misspellings through: https://twitter.com/maybekatz/status/892501201551368192
iamakulov··on Malicious crossenv package on npm
It’s of 19th July :–(
iamakulov··on Malicious crossenv package on npm
For everyone, here’s a one-liner to check your dependency tree:

    npm ls | grep -E "babelcli|crossenv|cross-env.js|d3.js|fabric-js|ffmepg|gruntcli|http-proxy.js|jquery.js|mariadb|mongose|mssql.js|mssql-node|mysqljs|nodecaffe|nodefabric|node-fabric|nodeffmpeg|nodemailer-js|nodemailer.js|nodemssql|node-opencv|node-opensl|node-openssl|noderequest|nodesass|nodesqlite|node-sqlite|node-tkinter|opencv.js|openssl.js|proxy.js|shadowsock|smb|sqlite.js|sqliter|sqlserver|tkinter"
(More details: https://iamakulov.com/notes/npm-malicious-packages/)