1,091 karma · joined August 13, 2013
My wife also got the same result, so I'm guessing it wasn't just because I was using my personal Claude account. Spooky stuff.
If it takes 17 rounds of review from 5 different models/harnesses – I don't care. Just spit out the right code the first time. Otherwise I'm wasting my time clicking "review this" over and over until the PR is worth actually having a human look at.
The first six months were hell because I kept focusing on how awful it was. Eventually you stop noticing it. It just becomes part of the background – like how the sky is blue, grass is green, etc.
I strongly recommend reading "Living with Tinnitus" by Laura Cole. Tinnitus is a very poorly-understood condition, but hearing about the experiences of others helps a lot. I hope you feel better soon. https://www.goodreads.com/book/show/37707931-living-with-tin...
I was not surprised for example that Marko came out very well in this performance comparison: https://www.lorenstew.art/blog/10-kanban-boards
The TL;DW is: yes, class selectors are slightly more performant than attribute selectors, mostly because only the attribute _names_ are indexed, not the values. But 99% of the time, it's not a big enough deal to justify the premature optimization. I'd recommend measuring your selector performance first: https://developer.chrome.com/docs/devtools/performance/selec...
Alternative approaches that may work for your use case:
- "HTML web components" [1] - light DOM only, SSR-first, good as a replacement for "jQuery sprinkles"
- "Shadow gristle" [2] - use as little shadow DOM as possible. If you need styling or composition, put it in the light DOM!
- Not every web app is perf-sensitive to every extra kB (eCommerce is, productivity tools typically aren't)
- Plenty of frameworks have tiny runtimes, e.g. Svelte is 2.7kB [2]
- I wouldn't advocate for 100 different frameworks on the page, but let's say 5-6 would be fine IMO
No one is arguing that this is ideal, but sometimes this model can help, e.g. for gradual migrations or micro-frontends.
BTW React 17 actually introduced a feature where you could do exactly this: have multiple versions of React on the same page [3].
[1]: https://nolanlawson.com/2021/08/01/why-its-okay-for-web-comp...
[2]: https://bundlephobia.com/package/svelte@4.2.19
[3]: https://legacy.reactjs.org/blog/2020/10/20/react-v17.html
> Maybe in the future, when you can render 3 different web component frameworks on the server, and they compose together and hydrate nicely, then I’ll consider this solved.
[1]: https://nolanlawson.com/2023/08/23/use-web-components-for-wh...
Obviously a lot of these techniques are pretty novel, and maybe they won't stand the test of time. Or maybe a new browser standard will make them obsolete eventually. But for now these seem to be the current wave anyway.
I did indeed mix up `useMemo` and `React.memo` – fixed it in the post.
You're right, I am skipping a lot of details (hence "to grossly oversimplify"). I know that React doesn't invalidate the whole tree, but it does in the worst case. Maybe I should add a note about that.
Svelte not being truly reactive makes perfect sense, but in Svelte v5 my understanding is that "runes mode" does exactly that. This is what I mean by "moving in that direction."
Also, it's still possible to shoot yourself in the foot, especially if you have a large/complex stylesheet repeated across multiple shadow roots. (Not because of the repetition – that's optimized in browsers [1] – but rather because of the number of DOM nodes affected.)
That said, I still think the perf benefits of shadow DOM have been undersung. And Declarative Shadow DOM makes it way more useful.
[1]: https://github.com/whatwg/dom/issues/831#issuecomment-585489...
It should be possible to build an "MPA" where all the rendering logic lives in the Service Worker. Then you'd get fast navigations without needing to worry about a client-side router and managing focus/scroll/etc. I'm not sure I've seen a great implementation of this though.
However, if you're adding event listeners to the document, the window, or some permanent element (header, footer, etc.), then those won't be GC'ed since the DOM node is never GC'ed.
I'm not an expert in this space, but it seems to me that the JavaScript engine could eventually clean up that memory, maybe based on some heuristics (e.g. the size of the original string, whether any references to the original string exist, etc.).
I would love to see how your tool approaches this! Hope it gets open-sourced. :)
The biggest problem is that yeah, WebSQL tends to be faster than IndexedDB. Or at least it was back when I was working on PouchDB. Biggest issue IIRC was that joins were faster in SQLite than implementing the same thing in userland on top of IndexedDB. Browsers eventually shipped getAll/getAllKeys which also helped with cursor slowness.
I haven't looked much at the Storage Foundation API [1], but it seems like a more reasonable approach moving forward. Just give developers the low-level tools and let them build SQLite on top of it. Also the Chromium devs have been working on relaxed durability, which apparently improves IDB perf in some scenarios [2] (although still not as fast as Firefox it seems [3]).
[1]: https://github.com/WICG/storage-foundation-api-explainer
[2]: https://www.chromestatus.com/feature/5730701489995776
[3]: https://bugs.chromium.org/p/chromium/issues/detail?id=102545...
Interestingly, the reason is (as I discovered) that most of these tools consider cross-origin requests as a signal of a third-party tracker or ad, and therefore block it. Pinafore works by talking directly to the instance's API, and so the instance itself is suspected to be a third-party tracker. ️
Most instances would federate with you immediately since they're on a blacklist model, but some instances (such as awoo.space) operate on a whitelist, meaning they'd have to vet you first.