Today’s issue: Making good on our Rust bounty, evolving the infinite canvas, and creating shaders for the god-king of late-stage capitalism.
Welcome to #242.
Me showing off my blog that uses every experimental Next.js feature and has 0 posts
I’m usually pretty suspicious when people promise me that something is “the best of both worlds” — and not just because I’ve had the Hannah Montana theme song stuck in my head since 2007.
It’s because whenever someone comes up with a new rendering method (or recycles one from PHP), we get a dozen articles about how ISR/Jamstack, or SSR, or Edge SSR are finally going to give us “the best of both” static and dynamic worlds.
But according to Sebastian Markbåge and Malte Ubl, it’s different this time with Partial Prerendering.
The two incredibly respected Vercel engineers just wrote about how this new feature in Next.js has the potential to become “the default rendering model for web applications,” because of the unique way it combines static edge delivery with fully dynamic capabilities on the same page.
Let’s take a closer look at how it works and what makes it unique from other rendering strategies.
How PPR works:
It serves a static route shell from the end-user’s nearest edge region immediately, so they can start using the page ASAP.
The shell leaves holes where slower, dynamic content can be streamed in later. Developers use React’s <Suspense />
boundary to designate what is static vs dynamic.
The async holes are dynamically rendered in parallel using React’s new streaming architecture, reducing overall page load time (see demo).
How it’s different: Unlike today, where entire routes are either fully static or dynamic, PPR provides one unified rendering model that lets you deliver content to users directly from the edge, fetch data without expensive waterfalls, and update the static shell via ISR.
In doing so, Sebastian and Malte claim that it’s able to eliminate all of the tradeoffs presented by other rendering methods.
Bottom Line: PPR is still experimental in Next.js 14, but we’ll soon find out whether it really is the best of both worlds, or if it’s just another Achy Breaky mistake in the evolution of web development.
Me and my team have way more time for activities now :)
That’s because they give you one unified platform for analyzing, testing, observing, and deploying new features.
We counted at least 7 different tools inside PostHog, but here are three of our favorites:
Product analytics let you easily find the data you want about user paths, retention, lifecycle analysis, and way more.
Surveys let you easily collect in-app feedback from your users with multiple question types and effective user targeting.
Feature flags allow you to safely roll out new features to specific user cohorts (and instantly roll them back, if necessary).
PostHog is a legit open-source company (14,500 GH stars with 411 contributors), and they’re beloved by both indie hackers and big companies like Hasura, Airbus, and Y Combinator.
Try out the generous free tier to get your first 1 million events per month for free.
Their guide on Enhancing Cloud Database Security in PostgreSQL outlines the process of configuring IAM database authentication within Cloud SQL.
<html lang="en">
<body>
<user-profile id="profile" username="JohnDoe"></user-profile>
<script>
class UserProfile extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
}
connectedCallback() {
this.render();
}
render() {
this.shadowRoot.innerHTML = `
<p>Username: ${this.getAttribute("username")}</p>
`;
}
}
customElements.define("user-profile", UserProfile);
setTimeout(() => {
document.getElementById("profile").setAttribute("username", "JaneDoe");
}, 3000);
</script>
</body>
</html>
The State of JavaScript Survey is open now. I highly recommend voting for Bytes and any other ui.dev properties you enjoy in the Resources
section. It’s a great way to express your appreciation and simultaneously inflate our team’s ego. Best of both worlds.
Amelia Wattenberger created a beautiful, interactive article/web experience called Evolving the infinite canvas.
Simplify debugging with Console Ninja’s Predictive Logging. Smart predictions and ahead of time logging saves you multiple iterations of adding logs and re-running your app to get the values you need. Never think “I wish I had logged that as well” again! [sponsored]
Biome claimed the $25,005 bounty for rebuilding Prettier in Rust. To be fair, they kind of had a three-year head start on everyone else, but we’re still happy to Venmo them our generous portion of the bounty.
The first Astro 4.0 beta was just released, which includes a Vite 5 upgrade and some other new features coming soon.
Jake Lazaroff wrote an article called Web Components Eliminate JavaScript Framework Lock-in, where he built a WC app where every single component is written with a different JS framework. Mad lad.
Nader Dabit created React Native AI, a full-stack framework for building cross-platform mobile AI apps.
New Relic just launched AI Monitoring (AIM) for early access. It’s the first monitoring solution that provides end-to-end visibility for any AI-powered application, so you can build and run safe, secure, and responsible AI apps with confidence. [sponsored]
Zach Leatherman wrote about A new technique for image optimization: SVG short circuiting.
Alexandre Devaux created a cool demo for creating shaders that lets you write your code and see it live on the Las Vegas Sphere. And because The Sphere is the benevolent god-king of late-stage capitalism, he will reward you handsomely for decorating him with beautiful shaders.
The observedAttributes
static getter and attributeChangedCallback
method are missing. Without these, the component will not react to changes in its attributes after the initial render.
<html lang="en">
<body>
<user-profile id="profile" username="JohnDoe"></user-profile>
<script>
class UserProfile extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
}
connectedCallback() {
this.render();
}
static get observedAttributes() {
return ["username"];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === "username") {
this.render();
}
}
render() {
this.shadowRoot.innerHTML = `
<p>Username: ${this.getAttribute("username")}</p>
`;
}
}
customElements.define("user-profile", UserProfile);
setTimeout(() => {
document.getElementById("profile").setAttribute("username", "JaneDoe");
}, 3000);
</script>
</body>
</html>