Stuffing 8 Safari releases into one

4 hours ago 1

Bytes

Today’s issue: Thousands of grainy JPEGs, shadcn/ui creator reveal, and Cloudflare developers keeping their eyes on the prize.

Welcome to #403.


Eyeballs logo

The Main Thing

Patrick Starr praying

Me asking Steve Jobs when they'll release the U2 (RED) version of Safari

Stuffing 8 Safari releases into one

Naming things is always hard for big companies, but numbering things hasn’t been much easier for Apple.

So it was nice to see them officially declare Version Number Bankruptcy™️ at this month’s WWDC – and choose to unify macOS 15, iOS 18, visionOS 2, watchOS 11, and Safari 18 on v26 (to match the year 2026). They’ll each get upgraded to v26 sometime this fall and will get annual version bumps to stay in sync going forward.

But after reading the 7,000-word announcement post for the new Safari 26 beta, I’m pretty sure that the Safari team of overachievers saw this as a chance to ship eight versions’ worth of features all at once. And I’m not complaining!

This mega-update comes with 67 new features and 107 additional improvements. Here are five we’re most excited about:

  1. SVG favicons - This long-awaited feature lets you harness the power of infinite vector scaling to get cleaner icons, smaller file sizes, and better support for different UI placements.

  2. Big CSS upgrades – New anchor positioning makes popovers and tooltips easier than ever, scroll-driven animations bring timeline control to CSS, and the contrast-color() function allows the browser to pick a contrasting color for you

  3. HDR image support – You can now embed HDR images directly into webpages, with CSS controls to balance them against SDR content

  4. WebGPU support – This JavaScript API provides faster, more modern GPU access for 3D rendering and compute-heavy tasks, allowing you to more efficiently leverage 3D frameworks like Babylon.js, Three.js, and Unity

  5. Trusted Types and JS cleanup – The new Trusted Types API blocks XSS by default, and new JavaScript methods like @@dispose let you safely clean up resources

Bottom Line: Martha Stewart once said that “software that gets versioned together, works together.” We’ll see if that’s true when I try to anchor-position a modal inside a popover inside a scroll-tied animation inside a WebGPU-powered canvas on my mom’s 2013 iPad Mini.


QA Wolf logo

Our Friends
(With Benefits)

Bobby Hill with Hank Hill's face photoshopped on

Finding out that your team’s entire QA process is just one guy named Greg clicking around in staging

Speed up your team’s release cycles – the easy way

What if you could press a button to help your team start shipping twice as fast?

That’s exactly what QA Wolf did for Drata, who now has 86% faster QA cycles with 4x more test cases (see the case study) – and they’ve done it for hundreds of other teams too.

Here’s how it works:

  • Their multi-agent AI systems create, maintain, and run Playwright tests for you

  • They provide unlimited parallel test runs on their infrastructure, so you get pass/fail results within 3 min

  • You get zero flakes, because every failed test is reviewed by one of their human QA engineers

Get a personalized demo – and see how their average customer increases their team’s release cadence by over 5x.


Spot the Bug logo

Spot the Bug

Sponsored by Sentry

They’re hosting this free AI in Production workshop on July 9th to give you hands-on experience at debugging AI-integrated applications and agents with full-stack visibility.

const enrichEvents = (events) => { const metadata = { usr_789: { tier: "premium", joined: "2023-04-01" }, }; const enriched = events.map(event => { id: event.id, time: event.time, user: metadata[event.userId], value: event.properties.totalValue } ); return enriched; }; const events = [ { id: "evt_123", time: "2024-12-10T10:00:00Z", userId: "usr_789", properties: { totalValue: 99.99, }, }, ]; console.log(enrichEvents(events));

Cool Bits logo

Cool Bits

  1. Sunil Pai and the Cloudflare crew wrote about how you can connect any React app to an MCP server in three lines of code with the use-mcp hook. Props to them for staying productive, even though their personal net worth basically doubled in the past 60 days. (In $NET we trust.)

  2. Redis built the world’s fastest data platform so your AI agents don’t have to sit around waiting for data like it’s 2008. Agent memory, semantic caches, real-time data delivery — all at sub-millisecond speed. [sponsored]

  3. Ernie Smith wrote a cool and historical post on Why JPEGs still rule the web after 30 years. It gave me new appreciation for the thousands of grainy JPEGs I dig through on cursed forums to find memes for this newsletter.

  4. Astro 5.10 comes with experimental live content collections that allow you to fetch content at runtime instead of build time.

  5. The creator of shadcn/ui (whose given Christian name is shadcn) wrote some interesting and nuanced thoughts on Radix, component libraries, and shadcn/ui.

  6. William Candillon wrote about the future of React Native graphics and how WebGPU is changing the game.

  7. Matt Smith wrote about using await at the top level in ES Modules

  8. Hurl is a command line tool that lets you define and run HTTP requests in plain text, which is great for testing and automation. I’d also like to announce that I’ve raised $100 million to build a Hurl-based wrapper platform and hired T-Pain to perform at our first conference.


Spot the Bug logo

Spot the Bug: Solution

Most likely your IDE would catch this one for you, but there is a syntax error. The map function is an arrow function that implicitly returns the result of the expression inside the block. In this case, the block is not a valid expression, so the code will throw a syntax error. To fix this, you can wrap the object in parentheses to make it an expression.

const enrichEvents = (events) => { const metadata = { usr_789: { tier: "premium", joined: "2023-04-01" }, }; const enriched = events.map((event) => ({ id: event.id, time: event.time, user: metadata[event.userId], value: event.properties.totalValue, })); return enriched; }; const events = [ { id: "evt_123", time: "2024-12-10T10:00:00Z", userId: "usr_789", properties: { totalValue: 99.99, }, }, ]; console.log(enrichEvents(events));
Read Entire Article