The least glamorous part of this repo is probably the most representative part.
Recovered the site from toolchain drift by pinning dependencies, vendoring unstable pieces, and treating maintenance work as part of the product instead of background cleanup.
This article is a retrospective written later, but it centers on the maintenance phase that started in 2021 and continued through later cleanup and vendoring work.
The big recurring problem was not inventing a clever layout or writing a nice article. It was keeping a custom publishing stack alive while Gatsby, React, plugins, and transitive dependencies all moved at different speeds.
This is where the repo history gets extremely honest.
The blunt version of this maintenance era is simple: I came back and I could no longer build my site.
That shows up in two of the best commit messages in the repo:
Big ole code rot fightoffClear out 3 years of tech debtThose are not exaggerated.
I had updated packages to current versions and immediately found myself in a long dependency repair effort. Notebook rendering was especially frustrating. Gatsby internals had moved, plugin APIs had shifted around, and smaller dependencies had not kept pace.
This is the part of software work that tends to disappear in polished case studies. In reality there was a lot of ugly in-between work with local checkouts, yarn link, hacked dependency versions, and debugging repos in place before I committed a working state.
The git history mostly catches the moment after I had already crawled out of the hole.
This was the phase where it would have been easy to tell myself a dramatic story about starting fresh.
I decided pretty explicitly not to do that.
I did not want to fall into the rewrite fallacy.
That mattered because the repo already contained a lot of hard-won publishing behavior. Rewriting into some new framework might have felt emotionally cleaner, but it would also have thrown away a lot of accumulated domain-specific knowledge.
So instead I kept the repo and moved the integration problems closer.
package.jsonThe clearest example is the notebook stack getting pinned to GitHub commits during repair work.
From the notes around that May 2021 recovery work:
"@gatsby-contrib/gatsby-transformer-ipynb": "https://github.com/sdobz/gatsby-transformer-ipynb#f2a60fd",
"@nteract/notebook-render": "https://github.com/sdobz/notebook-render#ec5a226"
and then in resolutions:
"@gatsby-contrib/gatsby-transformer-ipynb/@nteract/notebook-render": "https://github.com/sdobz/notebook-render#ec5a226"
That is not elegant, but it is very real.
There is also upstream evidence for why this happened:
The main thing I want to emphasize here is that maintenance pain was not coming from one dramatic failure. It was coming from relationships between packages.
That is why I say complexity is the number of relationships. A lot of these fights were not about huge codebases. They were about too many little pieces needing to agree at once.
As the repo got older, I got less interested in maintaining elegant distance from upstream and more interested in getting the site back under control.
That is how local plugins and vendored code became a normal part of the architecture.
By the later phases the repo includes things like:
plugins/gatsby-plugin-matomoplugins/gatsby-plugin-prefetch-google-fontsplugins/gatsby-remark-jupyterplugins/gatsby-remark-obsidianplugins/presentational-componentsEach one has its own reason.
Some were vendored because upstream was frustrating to manage. Some because I wanted small logic changes. Some because I kept needing updates and did not want the overhead of a separate fork. Some because the original behavior simply did not match my workflow.
A good later example is presentational-components.
Vendoring presentational-componentsFix presentational-componentsThe root problem there was pretty practical: I needed a newer React for Gatsby, and the upstream package depended on an older React. I did not want to fork a large monorepo just to make a relatively mechanical compatibility update.
So I extracted the part I needed, committed a pristine vendored copy first, and then modified it locally.
That workflow matters to me:
That gives me a clean diff of what I changed. If I get lost, I can back out my patch without losing the imported baseline. If I later decide to upstream something, I can see exactly what the patch is.
It is not glamorous, but it is sane.
plugins/gatsby-remark-obsidian/index.js is a good example of the kind of customization I eventually wanted to own directly.
For example, this bit resolves wiki-style image embeds by filename:
node.value.matchAll(obsidianReference).forEach(([full, filename, label]) => {
const isEmbed = full.startsWith("!")
const file = filesByBase[filename]
if (!file) {
reporter.warn(`${full}: ${file} not found`)
return
}
// ...resolve relative path and insert an image node...
})
The practical goal was simple: support embeds like this in markdown:
![[image.jpg]]
I wanted those embeds to resolve through Gatsby file nodes using a simple filename map instead of forcing path-heavy references everywhere. That makes content more resilient to reorganizations.
That is the kind of feature that sounds tiny until you notice how much smoother it makes authoring.
There is a personal cost here that the code does not show very well.
After the code-rot fightoff I had very little energy left to add new content. I was burned out from repair work.
That is worth saying because maintenance is not just technical. It affects whether the project still feels inviting.
If every return to the repo starts with dependency archaeology, the repo stops feeling like a writing tool and starts feeling like a chores folder.
A lot of the later work was shaped by not wanting to repeat that experience.
I was not especially disciplined about proactive drift detection during the worst of this. If I were formalizing it now, I would add regular build checks and dependency audits so breakage gets caught while it is still small instead of after a long gap.
This phase taught me something I still believe pretty strongly: if a system matters to your workflow, you eventually need to own the seams.
Not every seam. That way lies madness.
But the important seams? Yes.
If your publishing stack depends on plugins that drift, nested package relationships that break quietly, or ecosystem corners that nobody is maintaining with your exact use case in mind, the practical move is often to pull the critical pieces closer until the system becomes debuggable again.
That is not as shiny as a rewrite. It is usually more useful.