Astro's Hybrid Theory

Issue #324.September 19, 2024.2 Minute read.
Bytes

Today’s issue: Pauly Shore learns Rust, JavaScript is a gateway drug, and my mom gets nervous about me using TanStack Router.

Welcome to #324.


Eyeballs logo

The Main Thing

Linkin Park's Hybrid Theory album cover with the Astro logo

Render one step closer to the edge, and I’m about to break

Astro’s Hybrid Theory

I’m a big believer in the Astro team for two main reasons: 1) they ship a lot, and 2) Fred K. Schott’s beard communicates authority.

Both of those attributes were on display this week with the Astro 5 beta release, which doubles down on Astro’s commitment to type safety and hybrid rendering. Let’s break it down.

Type safety: v5 comes with type-safe environment variables that allow you to define a schema for your environment in astro.config.js. This sets the context for where the variable can be accessed from (client vs server) and whether or not the variable is private or public. Then you can access the variable using astro:env/client or astro:env/server.

Astro introduced “Content Collections” back in version 2, which brought type-safe Markdown and MDX to the framework. They’re taking that idea one step further in v5, with a new Content Layer API that lets you define a schema for any type of content – whether it comes from a CMS, API, or local files.

Hybrid rendering: In Astro 5, every page is statically generated by default, until you opt out of pre-rendering with export const prerender = false;. But you can also set SSR as the default by changing output: 'server' in your Astro config.

Server Islands are now stable in v5, and they take this one step further by enabling hybrid rendering at the component level. This lets you render individual components on the server even if the rest of your site is served statically from a CDN.

Bottom Line: Right now, Astro feels like one of the only frameworks that’s shipping innovative new features on a regular basis. Yes, it’s easier to do that as an earlier-stage project, but it’s still impressive and inspiring to see – just like Fred’s facial hair.

        

Sanity logo

Our Friends
(With Benefits)

Goofy squinting his eyes and saying, Oh Naw

When you’re 7 weeks into your 2-week custom CMS sprint

Building with Next.js? Then you need to think about content

It doesn’t matter if you’re just connecting to a database or parsing markdown files into an AST – how you handle your site’s content is crucial.

That’s where Sanity comes in. It’s a content operating system that gives you everything you like about databases, while making it easy for anyone on your team to manage and edit content.

They’ve built deep integrations with Next.js to offer the industry’s best Visual Editing experience, which works seamlessly with all your components (including RSC).

And now, they’ve taken those learnings and created a track of free courses that teach you how to build enterprise-quality content sites with Next.js and Sanity.

You can use the Sanity free tier for all the courses, or you can use this special Bytes link to get an extended trial of the Growth plan.

Check out the courses.


Spot the Bug logo

Spot the Bug

Presented by Clerk

They just released this well-written guide on How to combine the benefits of session tokens and JWTs to create the optimal auth strategy for your app.

What gets logged?

class BankAccount {
  constructor(initialBalance) {
    this.balance = initialBalance;
    this.minimumBalance = 20.00;
  }

  deposit(amount) {
    this.balance += amount;
  }

  withdraw(amount) {
    if (this.balance - amount <= this.minimumBalance) {
      return false;
    } else {
      this.balance -= amount;
      return true;
    }
  }

  getBalance() {
    return this.balance;
  }
}

const myAccount = new BankAccount(150.00);
myAccount.deposit(0.10);
myAccount.deposit(0.20);

myAccount.withdraw(130.30);
console.log(myAccount.getBalance());

Cool Bits logo

Cool Bits

  1. Ashley Claymore just released ts-blank-space – a brand new type-stripping compiler that’s 5.6x faster than tsc thanks to zero codegen, written in TS, and can make the bad types good for a weekend.

  2. Building reliable software goes beyond code. Dr. Panos Patros broke down the three key principles that keep engineering teams on track – Quality, Autonomy, and Support. [sponsored]

  3. date-fns v4.0 comes with first-class time zone support and no major breaking changes.

  4. Charlie Gerard wrote about how she figured out how to hack cars using JavaScript. I guess my mom was right, JavaScript was a gateway drug all along.

  5. Fastify v5 was officially released yesterday to simplify long-term maintenance and streamline the framework by removing all deprecated APIs.

  6. The HTTP Workgroup just proposed a new HTTP method called QUERY that provides a “safe and idempotent request method that can carry request content.” If you’re the type of person who prefers to not use the word idempotent in polite company, you can think of QUERY as a new middle ground between GET and POST.

  7. Apryse created this step-by-step guide to building an embedded PDF viewer in a PHP app for free with two different methods. [sponsored]

  8. Christopher Horobin wrote an article on the TanStack Blog about how TanStack Router pushes the boundaries on type-safe routing. Just please don’t push the boundaries too hard, or else my mom won’t let me use it.

  9. Safari 18 joins Chrome in supporting View Transitions and Style Queries 🎉.

  10. Biome just released v1.9 and celebrated their first birthday. I got them a copy of Bio-Dome on VHS to celebrate – because nothing says “congratulations” quite like Pauly Shore and a 4% rating on Rotten Tomatoes.


Spot the Bug logo

Spot the Bug: Solution

Presented by Clerk

Answer: 150.29999999999998

We would expect to see 20.00, but due to floating point arithmetic in JavaScript, we get an unexpected result. To fix this issue, we can represent money as integers (e.g., cents) and use Math.round to avoid the pitfalls of floating-point calculations. Here is the updated code:

class BankAccount {
  constructor(initialBalance) {
    this.balanceCents = Math.round(initialBalance * 100);
    this.minimumBalanceCents = 2000;
  }

  deposit(amount) {
    this.balanceCents += Math.round(amount * 100);
  }

  withdraw(amount) {
    const withdrawalCents = Math.round(amount * 100);

    if (
      Math.round(this.balanceCents - withdrawalCents) < this.minimumBalanceCents
    ) {
      return false;
    } else {
      this.balanceCents -= withdrawalCents;
      return true;
    }
  }

  getBalance() {
    return this.balanceCents / 100;
  }
}

const myAccount = new BankAccount(150.0);
myAccount.deposit(0.1);
myAccount.deposit(0.2);
myAccount.withdraw(130.3);

// Displaying the remaining balance, should be 20.00
console.log(myAccount.getBalance());