Rethinking best practices™️ at Next.js Conf

Issue #235.October 31, 2023.2 Minute read.
Bytes

Today’s issue: Self worth mantras, maintaining 1,000 npm packages, and how Yarn 4.0 made one NBA player unexplainably gain 35 pounds.

Welcome to #235.


Eyeballs logo

The Main Thing

3 guys dressed up in Powerpuff Girls costumes

The moment we learned that Next.js Conf was *not* a costume party

Rethinking best practices™️ at Next.js Conf

It’s an October tradition unlike any other, complete with all-black outfits, moody stage lighting, and more drama than Halloweentown 2.

Of course I’m talking about last week’s Next.js Conf, which produced a surprisingly huge amount of Twitter drama around Next.js 14, considering this release introduced exactly zero new APIs and only a few (small) breaking changes.

So what was all the fuss about? Mostly Server Actions, a React Canary feature that was first released in Next.js 13 but is now marked as stable in v14. They allow you to define a function that runs securely on the server, called directly from your React components.

function Bookmark({ slug }) {
  return (
    <button
      formAction=(async () => {
        "use server";
        await sql`INSERT INTO Bookmarks (slug) VALUES (${slug});`;
      })
    >
      <BookmarkIcon />
    </button>
  )
}

Admittedly my least favorite part of the conf was the vertigo I got being sent back to 2013 and having to, again, re-live everyone’s unearned opinions about a new technology they’ve never used.

Along with Server Actions, there were three other headliners of the new Next 14 release:

  • Turbopack is Vercel’s newish, Rust based bundler they first introduced at Next conf in 2022. We haven’t heard much about it since then, but recent benchmarks seem promising and once Vercel gets 100% test coverage for next dev, they’ll move Turbopack to stable in an upcoming minor release. If you’re a real sicko, you can follow along at areweturboyet.com or at our accompanying site, doineedtotouchgrasstoday.com.

  • Partial Prerendering (PP? 🌝🌘🌚) “builds on a decade of research and development into SSR, SSG, and ISR.” It’s a compiler optimization that generates a static shell based on your Suspense boundaries. The fallback elements you give to Suspense are prerendered and then replaced with dynamic components later on (via streaming). This gives you the ability to maintain a fast initial static response, regardless of if you have dynamic content.

  • To help you keep all those acronyms straight, they also announced nextjs.org/learn – “a complete guide to build with the App Router”.

Bottom Line: It was a fun throwback to see dev Twitter dunking on a new React feature that it doesn’t really understand. If history is any guide, this means that everyone will be using it a year from now.

        

clerk-logo

Our Friends
(With Benefits)

Two gummy bears holding hands with Clerk and Next.js logos

Bffs 4ever ❤️

Clerk is the best auth tool for Next.js apps

But it’s more than just auth. Clerk gives you customizable components with everything you need to onboard your users and let them manage their accounts.

These components work seamlessly in any tech stack, but they come with some uniquely powerful features for Next apps:

  • First-class support for Next.js App Router and RSC, so you can utilize server actions and route handlers for your auth (see docs)

  • An authMiddleware() helper that makes it easy to integrate Clerk features through Next.js middleware

  • Hooks and helpers for both the client and the server that let you read session and user data

If you’re looking for the best auth solution in a Next.js app, try out Clerk for free, and see why it’s one of the fastest-growing devtools out there.


Spot the Bug logo

Spot the Bug

Sponsored by JetBrains

Get up to speed with modern JavaScript and TypeScript in one day. JetBrains JavaScript Day 2023 is a free virtual event on Nov. 2, exploring latest trends with community experts. Register today!

const fetchPokemon = async (id) => {
  const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`);
  if (!response.ok) {
    throw new Error(`Network response was not ok: ${response.statusText}`);
  }
  const data = await response.json();
  return data;
};

const getStarterPokemon = () => {
  const ids = [1, 2, 3]
  const pokemon = [];

  ids.forEach(async (id) => {
    const result = await fetchPokemon(id);
    pokemon.push(result);
  });

  return pokemon
}

getStarterPokemon()

Cool Bits logo

Cool Bits

  1. The first ever State of React survey is now open. Go show some love for Bytes and react.gg in the “Resources” section. Or don’t. Our self worth isn’t dependent upon survey results.

  2. Convex is like the 2023 version of Firebase. It gives you a type-safe backend that can replace your database, server functions, and glue code. [sponsored]

  3. Jake Lazaroff wrote an article called Web Components Will Outlive Your JavaScript Framework. That might be true, but some of us are here for a good time, not a long time, Jake.

  4. Bun v1.0.7 comes with improvements to bun install and Node compatibility.

  5. Radek wrote about how he made JSON.parse() 2x faster.

  6. A Mozilla engineer created a new (WIP) browser engine from scratch entirely in JavaScript called Shadow.

  7. Unlayer Embed is a drag-and-drop email editor, page builder, popup builder and document builder for your SaaS application that’s white-label and easy to embed. It will easily save you months of dev time. [sponsored]

  8. Sindre Sorhus wrote Goodbye, Node.js Buffer about how he intends to move all his packages from using Buffer to Uint8Array. And since he actively maintains over 1,000 npm packages, that’s pretty noteworthy.

  9. Radix Vue just launched v1.0 of its Vue port of the Radix UI component library.

  10. Yarn 4.0 came out last week with a new Hardened Mode that performs two extra validations to protect you from common attacks. Not to be confused with Harden Mode, which is when an NBA player demands to be traded to a new team and unexplainably gains 35 pounds.


Spot the Bug logo

Spot the Bug: Solution

Sponsored by JetBrains

await-ing inside of a forEach will only end in pain. There are a few different ways to fix this, but here’s one using a for of loop.

const fetchPokemon = async (id) => {
  const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`);
  if (!response.ok) {
    throw new Error(`Network response was not ok: ${response.statusText}`);
  }
  const data = await response.json();
  return data;
};

const getStarterPokemon = async () => {
  const ids = [1, 2, 3]
  const pokemon = [];

  for (const id of ids) {
    const result = await fetchPokemon(id);
    pokemon.push(result);
  };

  return pokemon
}

await getStarterPokemon()