The Remix Chronicles

Issue #396.May 30, 2025.2 Minute read.
Bytes

Today’s issue: The only prescription for a broken metaframework, a more ruggedly handsome version of Tom Holland, and the simple joys of learning nothing from a big project.

Welcome to #396.


Eyeballs logo

The Main Thing

a retro army guy

My app still running React Router v4

The Remix Chronicles

I don’t talk about it often, but over my many years of writing software, I’ve developed what I’d consider to be a repeatable system for managing tech debt across large codebases.

Whenever you come across a codebase that you 1) didn’t write or 2) no longer understand, delete it and start over.

Is it practical? Is it realistic? Is this haunted room actually stretching?

Regardless, it seems that with their latest announcement, the Remix team is also a believer in my system.

But before we get to that, let’s take a quick detour to see how we got here.

First we started with React Router, then that split and we got Reach Router, then that merged back into React Router, then we got Remix, then Remix got tired and took a nap – which left us with React Router, but while Remix was napping it had one of those dreams where React cheated on it, and now it’s awake and wants nothing to do with React.

Instead, Remix v3 will be a fork of Preact, a mature virtual DOM library already used heavily at Shopify, and will focus on “simplicity, clarity, and performance”.

In other words, it’s an entirely new thing that has nothing to do with Remix, React, or React Router.

Bold, and that’s kind of the point. Because React Router has “a dedicated team, long-term backing, and an open governance model to keep it growing for years to come,” the Remix boys say they’re “free to go build what comes next”.

What exactly that means is still TBD, but they gave us some principles they’re hoping to abide by:

Model-First Development – Optimize the code, docs, tooling, and abstractions for LLMs

Build on Web APIs – Keep the entire stack on vanilla Web APIs + JavaScript to eliminate context-switching

Religiously Runtime – Design everything to execute unbundled at runtime

Avoid Dependencies – Minimize or entirely avoid third-party libs

Demand Composition – Ship small, single-purpose modules that plug in or drop out without issue

Distribute Cohesively Re-export those modules as one “remix” toolbox so adoption stays effortless

Bottom Line: If you didn’t want your spouse to be upset, you shouldn’t have cheated on them in their dreams.


QA Wolf logo

Our Friends
(With Benefits)

Edna Mode from the Incredibles staring into the camera

Me watching all my tests slowly fail one by one

The easy way to speed up your team’s release cycles

What if you could wave a magic wand to help your team immediately start shipping faster?

That’s exactly what QA Wolf has done for hundreds of companies – including Brilliant, who was able to cut their release cycles from 24 hours to 5 minutes (see the case study).

Here’s how it works:

  • They create, maintain, and run automated Playwright tests to cover your entire application, 5x faster than anyone else

  • They provide unlimited parallel test runs on their infrastructure and get you pass/fail results within 3 minutes

  • You get zero flakes, because every failed test is reviewed by their team of human QA engineers

Get a personalized demo for your team – and see how their average customer increases their release cadence by over 5x.


Spot the Bug logo

Spot the Bug

Sponsored by Redis

Configure and scale Redis 8 on the cloud in 2 minutes. Effortlessly hit 1 billion ops per second.

function flattenArray(arr) {
  let result = [];
  arr.forEach((item) => {
    if (Array.isArray(item)) {
      result.concat(flattenArray(item));
    } else {
      result.push(item);
    }
  });
  return result;
}

console.log(flattenArray([1, [2, [3, [4]]]]));

Cool Bits logo

Cool Bits

  1. Evan You just announced that Rolldown-Vite is now live and ready to bundle your Vite apps with the sweet nectar of Rust.

  2. TkDodo wrote about the beauty of TanStack Router, but he failed to mention how Tanner is a more ruggedly handsome version of Tom Holland.

  3. JavaScript Mastery created this 4-hour tutorial video on launching a SaaS app with Next.js, Supabase, and Clerk Billing – the easiest way to set up subscriptions in your application. [sponsored]

  4. Antirez wrote about how human coders are still better than LLMs, which is great news if your livelihood depends on that fact 🙃.

  5. The Syntax crew interviewed the creator of VS Code and the Copilot Lead about the future of VS Code and Copilot, now that it’s all open source.

  6. The RedwoodSDK team wrote about why your React meta-framework feels broken, and how the only prescription is more cowbell Redwood.

  7. Growl wrote about how Next.js server actions are public-facing API endpoints.

  8. The ESLint team wrote this retrospective on ESLint v9. Most teams only publish retros like this if something goes wrong, but my team prefers to write them when everything goes perfectly. “We released this thing, it does what we said it would do, we had no issues, and we learned nothing new from this experience. Enjoy.”


Spot the Bug logo

Spot the Bug: Solution

Sponsored by Redis

Array.prototype.concat() doesn’t mutate the original array, it returns a new array. To fix the issue, we need to assign the return value of result.concat(flattenArray(item)) back to result.

function flattenArray(arr) {
  let result = [];
  arr.forEach((item) => {
    if (Array.isArray(item)) {
      result = result.concat(flattenArray(item));
    } else {
      result.push(item);
    }
  });
  return result;
}

console.log(flattenArray([1, [2, [3, [4]]]]));