Skip to content

What five years of neglect does to a side project

· 4 min read

I built this site in July 2021, right after finishing a coding bootcamp, and then didn’t touch it for five years. When I opened the repo again in August 2026, it didn’t build. Not “had warnings” — the install itself failed before it got anywhere near the application code.

The specific failure is worth writing down, because it wasn’t caused by anything I did. It was caused by not doing anything.

The install died, not the app

gyp ERR! stack TypeError: Cannot assign to read only property 'cflags'
node_modules/node-sass  →  Build failed with error code: 7

node-sass compiles native code through node-gyp. It was deprecated in 2020, and the version I had pinned cannot compile against Node 18 or newer. The only reason it had ever worked on my machine was that my local Node was still v14.17.3 — a version that reached end of life in April 2023.

So the site had two clocks running against it. One was the dependency, frozen at a version that would never support a newer runtime. The other was my own environment, which happened to be old enough to hide the problem. As soon as I touched either, it broke.

The tell was in node_modules: it contained exactly two packages, both native image binaries. The install had crashed partway through and left the tree in a state that looked plausible from the outside.

Rot isn’t gradual

The thing I’d assumed about neglected projects is that they degrade — a deprecation warning here, a slightly wrong behavior there. That’s not what happened. It worked perfectly, right up until it didn’t work at all.

node-sass was the first wall, but not the only one:

  • Material-UI v4 was the pre-v5 package namespace. Its entire styling API — makeStyles, withStyles — doesn’t exist in React 18+. Not renamed. Gone.
  • prop-types was imported in a component but never declared in package.json. It resolved only because a dependency happened to hoist it. That’s not a dependency; that’s a coincidence.
  • sass-loader was installed and .scss was in the webpack test regex, but sass-loader was missing from the actual loader chain. A latent break that never fired because nothing imported a .scss file.
  • Every deployed link was dead. Heroku retired free dynos in November 2022, so all my project demos 404’d.

Each of these was fine in 2021. None of them were things I got wrong. They were bets on an ecosystem staying still, and it didn’t.

Rewriting was cheaper than fixing

I expected to migrate. I ended up rewriting, and the arithmetic was clearer than I thought it would be.

The site was 966 lines. Almost all of it was Material-UI tab plumbing — a single page with five tab panels, no routes, one URL. The actual content was about ten paragraphs of prose, three schools, a publication, and a project list.

Migrating meant porting a dead styling API to a new one, then still having a tab-panel architecture with nothing to link to and nothing for a blog to attach to. Rewriting meant moving ten paragraphs into a framework built for content. The thing I’d have been “saving” was the part with no value.

I moved to Astro, which builds to static files and treats Markdown as a first-class input rather than something you bolt on.

What the typecheck caught that the build didn’t

One detail from the rebuild stuck with me. Partway through, I put a comment in an invalid position inside a component’s attribute list. astro build accepted it and produced correct output. astro check reported eight cascading parse errors.

If CI had only run the build, that would have shipped. The typecheck is doing work the build isn’t, and I’d have assumed a green build was sufficient.

Same category of lesson as the node-sass failure: the signal you’re not collecting is the one that bites you.

What I actually changed

The concrete guards, in rough order of how much grief they prevent:

Guard Prevents
.nvmrc + engines The runtime drifting out from under the dependencies
npm ci in CI package-lock.json and package.json silently diverging
Typecheck as a separate CI step Errors a lenient build tolerates
Pinned deploy tooling A CLI release changing deploy behavior
A .gitignore node_modules/ being one git add . from the repo

That last one is embarrassing. The 2021 repo had no .gitignore at all. node_modules had stayed out of it purely by luck.

The part I’d tell 2021 me

Pick boring dependencies, and prefer ones with no native compilation step. node-sass is the whole argument on its own: dart-sass existed, was pure JavaScript, and would still work today. The choice between them looked irrelevant in 2021. It was the single decision that determined whether this project was alive in 2026.

And write down what the project needs to run. Not for anyone else — for yourself, five years later, when you’ve forgotten that the only reason it works is a Node version you’re about to upgrade.