Wtf is Waku?

Issue #316.August 22, 2024.2 Minute read.
Bytes

Today’s issue: Winning cash prizes with JavaScript and WD-40, code editors that appreciate poetry, and a new series of family-friendly films to teach your children wholesome, Nuxt-centric values.

Welcome to #316.


Eyeballs logo

The Main Thing

Cat in the Hat sneaking up on a kid while holding a bat

When the React team sees me building an app without a VC-backed framework

Waku beefs up

Waku just launched v0.21 on Tuesday, with full support for the React Server Actions API.

And if you’re not as terminally online engaged with the community as some of us, you probably have two questions right now: 1) Wtf is Waku? and 2) What does the React Server Actions API do? We got you covered.

Waku describes itself as “a minimal React framework” that’s specifically designed for building small to medium-sized React projects with React Server Components. It was created by the maintainers of Zustand and Jotai, and it’s currently the only React framework that supports RSC that doesn’t rhyme with Shrext.js.

Waku started off as a largely theoretical research project to explore RSC – but since we first wrote about it last year, the team has continued to add powerful new features that improve the DX while preserving its flexibility. They introduced a new file-based routing API back in March, and now they’ve got full support for Server Actions.

Here’s what that looks like:

  • First, you create server actions by using the use server" directive. This automatically creates an API endpoint for code to be executed securely on the server.

  • Next, you import your action into a client component that uses the use client directive, allowing you to pass data between the client and the server without any boilerplate.

  • Finally, you can read the state of the action using React APIs like useActionState to ensure you have the right UX in place during the action.

Bottom Line: Yes, you can already do most of this in Next.js. But now that the React team strongly recommends we all use a metaframework, it’s nice to have at least one other option for using RSC – at least until Remix catches up.

        

QA Wolf logo

Our Friends
(With Benefits)

Shrek looking sad

Mfw I'm forced to manually QA test my own code before I can ship it

QA Wolf gets you full end-to-end test coverage in 4 months

And it’s way less expensive than hiring a full-time QA team, and way more effective than forcing your engineers to do it themselves.

Here’s how it works:

  • They automate hundreds of tests for you in Playwright to test every single user flow, API, and third-party integration in your app.

  • They provide all the infra to run 100% of your test suite in parallel, so your team can test and deploy continuously.

  • They sort all the real bugs from the flakes with human-verified bug reports – so you never waste time on flaky tests.

QA Wolf helped Napster offset the need to hire 4 QA engineers, while boosting test coverage and developer happiness at the same time 😇.

Learn more about their 90-day pilot program – and see how they can help your team.


Spot the Bug logo

Spot the Bug

Sponsored by Raygun

Check out their Comprehensive guide to SPA performance to learn everything you need to address common perf issues that slow down most SPAs.

function deepClone(obj) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }

  const copy = Array.isArray(obj) ? [] : {};

  for (const key in obj) {
    copy[key] = deepClone(obj[key]);
  }

  return copy;
}

const objA = { value: 1 };
const objB = { a: objA };
objA.b = objB;

const clonedObj = deepClone(objA);

Cool Bits logo

Cool Bits

  1. The Nuxt team just released a beta version of Nuxt Scripts, which provides a new and improved way of working with third-party scripts. Not to be confused with Nuxt Screenplays™️ – a production studio I’m launching to create a new generation of family-friendly, Nuxt-centric films.

  2. Clerk created this in-depth guide to Role Based Access Control, so you can learn how to use RBAC to manage permissions in a large SaaS app without hating your life. [sponsored]

  3. David Kiss wrote an article called How I won $2,750 using JavaScript, AI, and a can of WD-40. I have no idea how David was able to perfectly recreate my bachelor party like this, but kudos to you, my friend.

  4. Nelson Elhage wrote about Stripe’s monorepo developer environment, based on his experience working there from 2012-2019.

  5. Michael Arnaldi wrote an article called From React to Effect, which explains how the mental model of the Effect TypeScript library closely maps to the concepts you probably already know in React.

  6. pkg.pr.new gives you continuous preview releases for your library, where each of your commits and PRs will trigger an instant preview release without publishing anything to NPM (it uses its own URLs instead). [sponsored]

  7. Pragtical is a new code editor that’s (wait for it) “practical and pragmatic.” Who says developers can’t appreciate poetry?

  8. Steven Levithan wrote an in-depth post about how Regexes got good, covering the history and future of regular expressions in JavaScript.

  9. Timo Lins and some other Vercel developers created little-date, a date range formatting library that’s “small and sweet.”

  10. Sunil Pai wrote about Spatial Compute, which he defines as “writing code for a server in ONE file, and having different parts of it run in different parts of the world depending on what’s best for the user.” Cloudflare employees only want one thing and it’s disgusting.


Spot the Bug logo

Spot the Bug: Solution

Sponsored by Raygun

The bug is that the deepClone function does not handle circular references. When objA is cloned, objB is cloned as well, which in turn clones objA again, and so on. This results in an infinite loop. To fix this, you can keep track of the objects that have already been cloned using a Map, and check if an object has already been cloned before cloning it again.

function deepClone(obj, map = new Map()) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }

  if (map.has(obj)) {
    return map.get(obj);
  }

  const copy = Array.isArray(obj) ? [] : {};

  map.set(obj, copy);

  for (const key in obj) {
    copy[key] = deepClone(obj[key], map);
  }

  return copy;
}

const objA = { value: 1 };
const objB = { a: objA };
objA.b = objB;

const clonedObj = deepClone(objA);