Building a San Francisco map feels a bit like cheating
I’ve always wanted a small, animated SVG map of just San Francisco. The city’s open data was already there. Codex made the rest feel easy.
Writing on Web Development, newest first.
I’ve always wanted a small, animated SVG map of just San Francisco. The city’s open data was already there. Codex made the rest feel easy.
ModHeader's ad injection put me off. I built ChHeader to edit HTTP headers without ads, with local profiles and source anyone can inspect.
The WP Engine fight, the Valkey fork, and agent-written code raise a harder question: what keeps an open-source project honest?
Removing SSR simplified Cubbly but delayed useful inventory. I compared four client-loading compositions and kept the one that made real route content 31–42% faster.
I removed React SSR from Cubbly because maintaining Lingui across the Worker and browser was not worth the speed it bought on a private application.
I wanted to keep a shared table component current without accepting migration work on faith. A side-by-side benchmark made the trade-off much easier to judge.
React Router v8 keeps the framework-mode API familiar and moves v7's future flags into defaults. That restraint matters after an expensive v6-to-v7 migration.
Grok Build produces useful patches, but its weekly limit changes how I use it. The harness and quota now matter more than the model.
Claude Code lowers the cost of being a Rust beginner. It kept two local-hardware projects moving while I learned the language inside them.
I keep changing this blog. One small Cloudflare Worker lets the URLs survive the changes while the site itself stays static.
Papra looked healthy on my NAS while registration failed. The browser hid the useful detail: SQLite belonged to the wrong user.
Biome keeps my AI coding loop moving, but it doesn't replace TypeScript. Here is the current setup and the trade-off I kept.
I expected Claude Code plugins to be heavy infrastructure. The frontend-design plugin is mostly Markdown; the marketplace makes it installable and scoped.
In Vite, ?url changes a JavaScript import into an asset URL import. Here is the fix—and when the suffix is actually useful.
jQuery 4 finally drops old browser baggage while keeping the DOM API that still earns its place in legacy interfaces.
Tailwind v4 rendered my shared components without their utility classes. One @source directive fixed three hours of monorepo debugging.
Six months with React Router loaders changed my default. I add React Query only when repeated fetching, shared data, or polling gives me a reason.
React Compiler 1.0 moved routine rendering memoization into the build. React.memo, useCallback, and useMemo now need a specific reason.
A small Cloudflare Worker can rewrite /tag/* to /tags/* without changing the main application or dropping query strings.
I moved a static site from Cloudflare Pages to Workers in five minutes. The config was easy; deciding whether a static blog benefits is harder.
How I deployed the React Router application with Fly.io, Cloudflare, Neon, Docker, and reviewable database migration history.
The React Router, TypeScript, PostgreSQL, and authentication stack I chose after using LLMs to prototype the alternatives.
Stale DNS stopped Fly.io issuing my origin certificate. Fixing that cleared the Cloudflare 525 error in this deployment.
The migration took two focused sessions: dependencies first, then 40 files of imports and route types. Typegen was the part worth keeping.
My Remix-to-React Router v7 migration touched 40 files and removed 591 net lines. Imports were easy; TypeScript took the time.
Leaving Next.js for Remix taught me why the annoying-looking use client boundary exists—and what Remix gives up without it.
My Remix app ran locally and failed on Vercel with EMFILE. The workarounds reduced file churn but could not expose or change the platform limit.
The package manager was the easy part. File APIs, CI, compatibility checks, and Claude Code produced most of the migration's useful work.
Moving this blog from Node.js to Bun cut its build from 37 seconds to 20. Native file and glob APIs also removed code I no longer needed.
OpenAI talked a ~$3B Windsurf deal. I use Claude Code and Cursor; the story that matters is who owns the IDE relationship, not the model API.
The benchmark gap was obvious, but deleting 90 lines of build configuration was the better reason to choose Vite for a modern app.
Claude Code helped build the parser, generator, templates, and Cloudflare deployment. Syntax highlighting and timezones took more work.
I paid about $10 to see whether Claude Code could scaffold the TypeScript static-site generator behind this blog. Most of its choices held up.
When Chrome began disabling uBlock Origin under Manifest V3, I stopped looking for another extension and moved my browsing to Brave.
A personal blog should be fast on a phone and boring to host — Markdown to static HTML on Cloudflare, no app server.
I started writing here again — web development, AI tools I actually run, and what SF startups taught me the expensive way.
The Apache module path was the easy-to-miss part of running Homebrew's PHP 5.6 on macOS El Capitan. Here is the full setup.
CORS failures that look unrelated often come down to request type, duplicate headers, or credentials. Here is how the browser treats each case.
Ubuntu 16.04 ships with PHP 7, which broke my WordPress. Here's how to upgrade PHP config and point nginx to the new php-fpm socket.
The exact S3 CORS configuration I used to make responses vary by origin instead of letting a CDN cache the wrong header.
Related subjects
Topics that appear alongside Web Development in these articles.
Back to the index