Today’s issue: Programming models that feel like cheating, critiquing my toddler’s TypeScript code, and becoming unbundled by what has been.
Welcome to #349.
React emerging from its cave (colorized)
Do any of you remember what you were doing 1,442 days ago? Probably not, but I do.
Michael Bublé’s sultry voice was playing through my parents’ Amazon Echo, artificial peppermint filled the air, and my entire family waited disappointingly for me to finish writing about “React on the Server” so I could finally join them for Christmas dinner.
Here we are nearly 4 years later, the family disappointment has subsided with the amount of ad spots we’ve sold, and with last week’s React 19 release, Server Components are officially stable and ready for primetime.
If you’ve managed to pull a Tiger King level of tuned out since 2020, Server Components are just React components that run exclusively on a server – whether that’s at build time on your CI server or with each request to your web server.
In doing so, React is able to improve performance by optimizing the initial bundle size of your app and streams the rest in later when it’s available.
Along with Server Components, React 19 came with a few other Holiday treats all React devs will enjoy.
Actions abstract the pain and monotony of handling async mutations by handling pending, error, and optimistic updates for you.
use
is a new API for reading resources directly in render. The two primary use cases for use
today are unwrapping promises that originate on a server, or reading values directly from context. Unlike useContext
, since use
isn’t a hook, you can use use
conditionally or in a loop.
ref updates: You can now access ref
as a prop directly without needing to use forwardRef
. And in my opinion the most underrated feature of React 19 is that ref
callbacks now support a cleanup function.
Bottom Line: I’d like to extend my deepest love and affection to the React team for releasing React 19 in early December before mamma gets in her ‘kerchief, and I in my cap, to settle down for a long winter’s nap.
When you see your auth bill double overnight
Their all-in-one platform gives you APIs and SDKs for auth and fraud prevention – and unlike other auth providers (*cough, Auth0, cough*), Stytch’s brand new self-serve pricing is fully transparent and dare we say, pretty reasonable?
Here’s how it’s different:
No feature gating – Every Stytch user gets access to every feature, even on the free tier. MFA, SSO, RBAC, and every other auth feature you can think of.
No hard caps or hidden fees – You only pay for what you use. The price doesn’t jump to a new tier if you cross an arbitrary cap.
Generous free tier – Stytch’s free tier offers significantly more than Auth0’s, and is designed to fully support your business’s first few years of growth.
Check out the free tier – and see why the co-founder of Mintlify said that “with Stytch, we cut time spent on auth to a tenth.”
We are expert US-based consultants who have specialized in high-quality React Native development since 2015! Hire us to build, optimize, deploy, and support your React Native app.
const blob = new Blob([`
self.onmessage = function() {
const processor = {
cache: new Map(),
process(data) {
return data.map(x => x * 2);
}
};
processor.cache.set('results', processor.process([1,2,3]));
processor.cache.set('processFn', processor.process);
self.postMessage({
type: 'DONE',
state: processor.cache
});
};
`], { type: 'application/javascript' });
const worker = new Worker(URL.createObjectURL(blob));
worker.postMessage('start');
worker.onerror = (e) => console.error('Worker error:', e);
worker.onmessage = (e) => console.log(e.data);
I decided to replace our family’s “Elf on a Shelf” with Advent of TypeScript. My 4 year old was pretty upset, but he’ll thank me once he realizes he’s the only kid in pre-K who knows how to use utility types.
MindStudio lets you quickly build and deploy serverless AI functions to handle all kinds of hard-to-code problems. It comes with a broad set of integrated tools to analyze, debug, optimize, and supervise your functions, with 50+ major AI models instantly available – or you can use your own. Over 100k functions deployed. [sponsored]
Corbin Crutchley wrote about Writing modern JavaScript without a bundler. It’ll give you a vision of what can be, unbundled by what has been.
Skia Canvas is a browser-less implementation of the HTML Canvas drawing API for Node.js.
Naman Goel (maintainer of StyleX at Meta) wrote his thoughts on Tailwind 4. Can I interest you in giving some feedback on TypeScript code written by a toddler, Naman?
Here’s a perfect holiday gift to give your team: 15-minute QA cycles with QA Wolf. They’ll help you ship faster and with fewer bugs, so it really is the gift that keeps on giving. [sponsored]
Phoenix LiveView 1.0 just launched, six years after the initial commit – and the creators say that its programming model “still feels like cheating.” If there’s one thing I’ve learned from Tiger Woods, it’s that if something “feels like cheating”, it probably is.
King TkDodo wrote about Ref Callbacks, React 19 and the Compiler.
Apryse’s PDF Optimizer lets you optimize PDF file size across all platforms without sacrificing quality – so your users can view shared documents online without waiting for the entire file to download 🙏. [sponsored]
Dan McKinley shared this talk he gave on Egoless Engineering. Now he needs to give a talk on id-less engineering, so I can silence my intrusive thoughts while I’m at work.
Lingui released v5.0 of its internationalization library.
Ankita Kulkarni made this 30-minute video reviewing TanStack Start vs. Next.js. If you’re a client-side app fan, get ready to ugly cry harder than you did during the last scene of Wicked.
The processor.cache
is a Map
object, which is not serializable. To fix this, you can convert the Map
to a serializable object before posting it to the main thread.
const blob = new Blob([`
self.onmessage = function() {
const processor = {
cache: new Map(),
process(data) {
return data.map(x => x * 2);
}
};
processor.cache.set('results', processor.process([1,2,3]));
// Convert Map to serializable object, skip functions
const serializableState = {
type: 'DONE',
state: Object.fromEntries(processor.cache)
};
self.postMessage(serializableState);
};
`], { type: 'application/javascript' });
const worker = new Worker(URL.createObjectURL(blob));
worker.postMessage('start');
worker.onmessage = (e) => console.log(e.data);