JSX could have been 2x faster if it was designed more optimally for JS VMs!
Let's see what design decisions make JSX slow and how we could speed it up.
🧵🪡🧶
Did you know that without 0x5F3759DF (magic number) Qake (the game) would not have been possible?
The fast inverse square root is 🤯 code popularized by Quake, which at first sight looks like complete nonsense.
Google: 0x5F3759DF
🧵🪡🧶
Amdahl's law: the nightmare of a perf engineer!
"The overall performance improvement gained by optimizing a single part of a system is limited by the fraction of time that the improved part is actually used"
After 15 years at Google and 10 years on
@angular
I am excited to announce that I am moving onto the next chapter in my professional life. I will be joining
@builderio
as their CTO to help empower anyone to create blazing fast sites, with some very exciting updates coming soon.
It's best to name your variables positively.
Negative variables take longer to process in your brain because they can be part of negated expressions, creating double negatives.
After months of hard work and community feedback, we are excited to announce Qwik RC!
V1 is just around the corner, so we would really value your feedback on this.
Find out more on our blog:
Hydration is a widely accepted solution to add interactivity to HTML, but we need to accept it for what it is: a clunky workaround.
It is time to move past hydration for a faster web:
Lazy-loading is like exercise. Everyone says they are doing it, few are, and those that are rarely know what they are doing.
Frameworks were not designed with lazy loading in mind. It was a late addition to their development life cycle.
We now pay the price of bloated apps.
/1
Understanding: useState() vs useSignal()
Signals scale better because they track subscriptions and render only the necessary components.
Signals are surgical!
State does not track who is listening and, therefore, must always re-execute all templates below it.
Everyone is excited about signals because of better DX and faster updates.
I am excited about signals because of the lazy execution of code => Better startup performance on slow networks and slow devices.
🧵
Blank page with an embedded tweet. How bad can it be?
JS: 1.5MB 🤯
PageSpeed score: 61/100 🤯
Time to Interactive: 9 sec 🤯
TBT: 1.7 sec 🤯
What hope does an average site have if a simple tweet requires MegaBytes of JS and seconds to interactivity?
It took me a long time to understand the value of React. Here are a few things that React nailed, and it is worth learning from.
- Components are functions
- Simplicity of JSX
- Composability of hooks.
- Explicitly not solving some things.
1/5
In engineering, rarely is A always better than B.
Usually, A and B come with a long list of PROS and CONS.
Your job as an engineer is to figure out which PROS matter and which CONS you can live with.
The curse of engineering is that everything is obvious after the fact.
The fact that it took you n weeks and a half dozen design docs to figure it out is instantly forgotten.
We don't download the whole movie before starting to watch it.
Why do we have to download the whole application before it becomes interactive?
Imagine a world where the Application could be streamed to you in the same way as Movies.
Software engineering is about tradeoffs.
Let's talk about how data fetching happens in different meta-frameworks and what the trade-offs of those approaches are.
Understanding how JavaScript Virtual Machines work can have up to a 60x performance impact.
Learn all about monomorphism and how it impacts performance in my latest blog post:
I have built a lot of frameworks that no one has ever heard of before one became popular.
- JS framework
- Pagelet: DI for MPAs
- ActionScript Flex Personal
- ActionScript Flex Work
- AngularJS <= This one became popular
Keep trying until you succeed!
Hydration is a horrible workaround because web frameworks don't embrace how browsers actually work.
Yet somehow we have turned it into a virtue.
Hydration is a hack to recover the app&fw state by eagerly executing the app code in the browser.
That is why your app is slow.
Why are all the meta-framework people suddenly talking about code extraction?
It is a new way to make your code more seamless and type-safe across the client and server.
I wrote about this and more of the exciting possibilities in my latest article:
What can Remix, Fresh, Astro, NextJS, and
@QwikDev
teach us about the performance of websites?
Let's dive into data and its implications => Performance is about not executing JavaScript!
🌶️ take
Both Angular and React are dirty checking frameworks! (Not reactive)
Angular dirty checks your data.
React dirty checks your vDOM.
PS: a good argument can be made that dirty checking data is cheaper then vDOM.
After months of hard work by
@manucorporat
,
@adamdbradley
, and the awesome Qwik community, we are finally here!
I can't express just how much joy this gives me. It is a start of a new era for web application development.
Slow apps can be made performant by:
- Lazy loading (load less)
- Lazy execution (do less)
- Memoization (don't redo work)
Most teams go through cycles of feature-dev and then optimization. But as soon as the optimization sprint is over, the app slowly regresses in performance…
Software engineering is constantly banging your head against what looks like unsolvable problems with suboptimal solutions.
Talk to people around you, sleep on the problems, and eventually, a beautiful and simple solution arises.
Persistence is the name of the game.
My need to build frameworks is completely irrational. I see a better way of doing it and I just have to do it! I told myself no more frameworks after Angular and here I am building Qwik.
As developers, we know how to serialize:
- Data => JSON
- Code => file.js
But how do you serialize closure (Code + Data)?
Qwik's key innovation, which enables all other magic, is that it knows how to serialize closures on servers and invoke them on clients, key to Resumability!
Want to know how
@QwikDev
delivers instant-on applications no matter the application complexity?
It's simple. Don't overwhelm the browser with 100s of KBs of JavaScript all at once, no matter how large your app gets.
It's how Qwik works.
People think that apps are hard to build because JavaScript sucks, so they keep inventing new languages that transpile to JavaScript.
The real reason is that we are missing proper abstractions, and that is why frameworks exist.
Awesome solutions are rarely created by committees or large organizations. It is almost always a single person with passion and vision that slowly infects others.
Mad props to
@youyuxi
and
@RyanCarniato
for making benchmarks on
@QwikDev
and then privately reaching out to us to let us fix issues. That is how OSS is supposed to work! Thank you, and I want to see more of this!
I constantly hear the misconception that
@QwikDev
/ Resumability is slow on the first interaction.
Let me show you real-world data and a demo showing you how instant it is.
But wait! Running the same tests in opposite order results in the opposite result?
Now, `b+a` is 3.6x faster than `a+B`? 🤯
Both can't be true! Welcome to JavaScript VM de-opt!
3/6
The problem with today's frameworks is not that it takes too long to render your shopping cart but that it takes too long before you can click it.
So why are we obsessed with rendering performance instead of startup performance?
I see a lot of comparisons of
@astrodotbuild
vs.
@QwikDev
on the web. Some of the characterizations, I disagree with it, so I wanted to share my point of view.
🧵
As the complexity of applications increases, the amount of JavaScript downloaded increases.
The only way we can continue building more complex web applications in the future is to lazy load on interaction, not on initial load.
Read more here:
Love the innovation that
@RyanCarniato
has placed in
@solid_js
. The reactivity composition is amazing.
I think all future frames will be fine grained reactive.
Let's assume: `x` is an Integer and `x = 0`
`0-x` => `0-0 => 0`, Result is `0` (Integer) Perfect!
`-x` => negate `x`.
- For any non-zero value, the result is an Integer.
- But for `0`, the result is `-0`. But integers can't have `-0`, So JavaScript stores it as a Float `-0`.
Not all lazy loading is created equal because most systems only have one entry point.
@QwikDev
is different because each bundle is an entry point.
This significantly reduces the amount of JS it needs to download or execute.
I have never seen a language that transpiles to JavaScript succeed. (And I predict I never will)
The semantic mismatch is never worth any marginal improvements!
TypeScript is JavaScript with no semantic mismatch, and that is why it is winning!
The JIT incorrectly assumed it was safe to inline `fnA` into the test harness, because the test harness always received the same `fnA` function. (monomorphic call site.) Inlined functions run faster.
4/6
But when `fnB` started running, the JIT realized its mistake (de-opt). Inlining was removed because the call is now sometimes `fnA` and sometimes `fnB` (polymorphic). So the second perf test ran without inlining (slower).
The second test appears slower!
5/6
What if I told you Angular is about to have a renaissance?
🎆 Angular just released a new Signals reactivity primitive and it's just the first step!
I made a little explainer about what it is:
The first thing to understand is that JavaScript has two representations for numbers:
- Integers: Fast path
- Floats (IEEE 754): Slower path
Integers are stored as “Two's complement” and can't have `-0`, but Floats can!
useState() returns the value "in time" rather than the state "over time" it represents. This can lead to problems when value is captured in closures such as useEffect().