Angular on the Server

Issue #344.November 22, 2024.2 Minute read.
Bytes

Today’s issue: Storming the United States Patent and Trademark Office, the Gatsby crew reunites, and if you’re looking for the Shadow DOM, it’s in the front.

Welcome to #344.


Eyeballs logo

The Main Thing

Woody evilly laughing

MFW I incrementally hydrate my Angular app for the first time

Angular on the Server

Despite being late to the game, the Angular team has been steadily improving their support for SSR over the last few years, culminating in this week’s release of version 19. But before we dive into all the new features, let’s take a quick look at how we got here.

After the bundle size wars of the late 2010’s, JavaScript frameworks started flocking to the server in search of better performance. Well, most of them… Angular didn’t add official support for SSR until 2023. And while this was a win, it still lacked some important features like support for different rendering modes and granular control over hydration. But that’s changing in v19.

Here are some of the key features from this release:

  • Route Level Render Modes: In Angular 19, you can choose between server side rendering, pre-rendering, and client side rendering for each route. In practice that looks something like this:
export const serverRouteConfig: ServerRoute[] = [
  { path: '/login', mode: RenderMode.Server },
  { path: '/dashboard', mode: RenderMode.Client },
  { path: '/**', mode: RenderMode.Prerender },
];
  • Incremental Hydration: Now Angular can render HTML on the server and then incrementally hydrate it on the client using event replay which queues up interactions that happen before hydration and replays them once the JS loads. This enables devs to selectively trigger when each component should hydrate or whether it should opt out.

  • Signals: While not related to SSR, Angular is doubling down on performance with signals. In v19 signals are now a “stable” feature and include new primitives like linkedSignal and resource which adds reactivity to your async data (basically @tanstack/react-query but built on signals).

Bottom Line: Now that Angular has signals and good support for SSR, it’s starting to look more like framework of the future than one of the past.

        

Neon logo

Our Friends
(With Benefits)

Dexter from Dexter's Lab with a chad head

Me after finding out that Neon 10x'd their free plan

Neon helps you ship faster with Postgres

All the cool kids love Postgres – but it can also be easy to get stuck battling complex configs, maintenance, and scaling issues.

That’s where Neon can help. They offer fully managed Postgres with features to help you build and scale faster – and they just 10x’d their free plan to give everyone ten projects:

  • Your DB automatically adapts to your app’s workload, eliminating the need for over-provisioning or manual resource allocation.

  • Seamlessly branch your data for development, testing, and more to improve developer productivity and optimize CI/CD pipelines.

  • Restore your database in seconds to any point in the past 30 days, 24 hours, or even 1 minute ago.

Try out the free tier, and provision your Postgres database in under a second – seriously, it’s that fast.


Spot the Bug logo

Spot the Bug

Presented by Infinite Red

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 products = [
  { name: "Shirt", price: 20, discount: true },
  { name: "Pants", price: 50, discount: false },
  { name: "Hat", price: 15, discount: true },
  { name: "Socks", price: 5, discount: true },
];

const discountThreshold = 30;
const discountRate = 0.1;

const totalCost = products.reduce((acc, product) => {
  if (product.discount) {
    if (product.price > discountThreshold) {
      acc += product.price * (1 - discountRate);
    } else {
      acc += product.price;
    }
  } else {
    acc += product.price;
  }
}, 0);

console.log(`Total cost: ${totalCost}`);

Cool Bits logo

Cool Bits

  1. The JavaScript nerds on Bluesky are storming the United States Patent and Trademark Office.

  2. Sentry just shipped a bunch of new features that you probably won’t hate during Sentry Launch Week. Check out this short video to get the highlights and a chance to win some surprisingly good Sentry swag. [sponsored]

  3. Some of the old Gatsby crew got back together to ship Mastra, a TypeScript AI framework “for the next million AI developers”.

  4. And for the current million non AI developers, the TypeScript team just announced TypeScript 5.7.

  5. The tailwind team just published Tailwind CSS v4.0-beta.1.

  6. QA Wolf gets your team 80% automated E2E test coverage and delivers real results that traditional QA services can’t match. Their customers average 5x more releases, 15-minute QA cycles, and 9 hours of engineering time saved per engineer per week. [sponsored]

  7. Sufian wrote about how the shadow DOM is in the front and the party is in the back, I assume.

  8. React Router v7 just shipped which “brings everything you love about Remix back into React Router proper”.

  9. Three developers who I know for a fact are very good at CSS discuss why we need better design tools on this edition of the Bad at CSS podcast.


Spot the Bug logo

Spot the Bug: Solution

Presented by Infinite Red

Total cost is undefined. The reduce function is missing a return statement. The reduce function should return the accumulator after the iteration is complete.

const products = [
  { name: "Shirt", price: 20, discount: true },
  { name: "Pants", price: 50, discount: false },
  { name: "Hat", price: 15, discount: true },
  { name: "Socks", price: 5, discount: true },
];

const discountThreshold = 30;
const discountRate = 0.1;

const totalCost = products.reduce((acc, product) => {
  if (product.discount) {
    if (product.price > discountThreshold) {
      acc += product.price * (1 - discountRate);
    } else {
      acc += product.price;
    }
  } else {
    acc += product.price;
  }
  return acc;
}, 0);

console.log(`Total cost: ${totalCost}`);