惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
S
Schneier on Security
The Hacker News
The Hacker News
P
Proofpoint News Feed
Spread Privacy
Spread Privacy
L
LINUX DO - 热门话题
L
Lohrmann on Cybersecurity
I
Intezer
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Schneier on Security
Schneier on Security
Security Latest
Security Latest
AWS News Blog
AWS News Blog
B
Blog RSS Feed
Microsoft Security Blog
Microsoft Security Blog
有赞技术团队
有赞技术团队
博客园 - 叶小钗
The Last Watchdog
The Last Watchdog
O
OpenAI News
月光博客
月光博客
Hacker News: Ask HN
Hacker News: Ask HN
阮一峰的网络日志
阮一峰的网络日志
S
Security @ Cisco Blogs
Google Online Security Blog
Google Online Security Blog
云风的 BLOG
云风的 BLOG
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Latest news
Latest news
P
Palo Alto Networks Blog
Last Week in AI
Last Week in AI
M
MIT News - Artificial intelligence
Google DeepMind News
Google DeepMind News
P
Proofpoint News Feed
C
CERT Recently Published Vulnerability Notes
Apple Machine Learning Research
Apple Machine Learning Research
U
Unit 42
PCI Perspectives
PCI Perspectives
博客园 - 聂微东
SecWiki News
SecWiki News
宝玉的分享
宝玉的分享
Forbes - Security
Forbes - Security
H
Heimdal Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Troy Hunt's Blog
博客园 - 三生石上(FineUI控件)
Application and Cybersecurity Blog
Application and Cybersecurity Blog
罗磊的独立博客
WordPress大学
WordPress大学
D
Darknet – Hacking Tools, Hacker News & Cyber Security

Kent C. Dodds Blog

Implementing Hybrid Semantic + Lexical Search Simplifying Containers with Cloudflare Sandboxes Migrating to Workspaces and Nx Offloading FFmpeg with Cloudflare Building Semantic Search on my Content Helping YOU ask ME questions with AI The Dow's Start on the Covenant Path 2025 in Review The next chapter: EpicAI.pro AI is taking your job How I increased my visibility Launching Epic Web 2023 in Review Stop Being a Junior RSC with Dan Abramov and Joe Savona Live Stream Fixing a Memory Leak in a Production Node.js App 2022 in Review My Car Accident I Migrated from a Postgres Cluster to Distributed SQLite with LiteFS I'm building EpicWeb.dev A review of my time at Remix Remix: The Yang to React's Yin How I help you build better websites Why I Love Remix The State Initializer Pattern How to React ⚛️ Get a catch block error message with TypeScript Building an awesome image loading experience How Remix makes CSS clashes predictable Introducing the new kentcdodds.com How I built a modern website in 2021 How to use React Context effectively Static vs Unit vs Integration vs E2E Testing for Frontend Apps The Testing Trophy and Testing Classifications Array reduce vs chaining vs for loop Don't Solve Problems, Eliminate Them Super Simple Start to Remix Super Simple Start to ESModules in Node.js JavaScript Pass By Value Function Parameters How to write a Constrained Identity Function (CIF) in TypeScript How to optimize your context value How to write a React Component in TypeScript TypeScript Function Syntaxes Listify a JavaScript Array Build vs Buy: Component Libraries edition Using fetch with TypeScript Wrapping React.useState with TypeScript Define function overload types with TypeScript 2020 in Review Business and Engineering alignment Hi, thanks for reaching out to me 👋 useEffect vs useLayoutEffect Super simple start to Firebase functions Super simple start to Netlify functions Super Simple Start to css variables Favor Progress Over Pride in Open Source Testing Implementation Details How getting into Open Source has been awesome for me useState lazy initialization and function updates Use ternaries rather than && in JSX Application State Management with React Use react-error-boundary to handle errors in React JavaScript to Know for React How I structure Express apps What open source project should I contribute to? When I follow TDD AHA Programming 💡 How I Record Educational Videos Should I write a test or fix a bug? Stop mocking fetch Intentional Career Building Improve test error messages of your abstractions Tracing user interactions with React Eliminate an entire category of bugs with a few simple tools Common mistakes with React Testing Library Super Simple Start to React Stop using client-side route redirects The State Reducer Pattern with React Hooks Function forms Replace axios with a simple custom fetch wrapper How to test custom React hooks React Production Performance Monitoring Should I useState or useReducer? Stop using isLoading booleans Make Your Test Fail Make your own DevTools An Argument for Automation Fix the "not wrapped in act(...)" warning Super Simple Start to ESModules in the Browser Implementing a simple state machine library in JavaScript 2010s Decade in Review Why users care about how you write code Why I avoid nesting closures Don't call a React function component Why your team needs TestingJavaScript.com Inversion of Control Understanding React's key prop How to Enable React Concurrent Mode How to add testing to an existing project Profile a React App for Performance
How I used Cursor to Migrate Frameworks
Kent C. Dodds 🏹 @kentcdodds · 2026-02-20 · via Kent C. Dodds Blog

Yesterday I decided it was time to upgrade the dependencies on kentcdodds.com (the site you're probably reading this on). I've actually been working on my site a bit recently to add a few new features (have you tried the new semantic search or keyboard shortcuts yet try "How did Kent get his first job?" and hit ? to see the keyboard shortcuts).

Just for context, kentcdodds.com is a pretty big project (currently sitting at over 42k lines of code with over 330k words of content). For a quick look at the scope of this thing, check out introducing the new kentcdodds.com for a high-level overview.

I gave Cursor (Composer 1.5) the following prompt:

Make me a list of packages in this project that are not on the latest version, grouped by difficulty of upgrading.

It gave me this table:

Here’s the list of outdated packages, grouped by upgrade difficulty:


Easy (patch/minor within same major)

Usually safe to upgrade with npm update or a small version bump.

PackageCurrentLatest
@conform-to/react1.16.01.17.1
@conform-to/zod1.16.01.17.1
@epic-web/config1.21.31.24.0
@modelcontextprotocol/sdk1.25.31.26.0
@playwright/test1.58.11.58.2
@prisma/adapter-better-sqlite37.3.07.4.0
@prisma/client7.3.07.4.0
@tailwindcss/vite4.1.184.2.0
@types/react19.2.1019.2.14
esbuild0.27.20.27.3
framer-motion12.29.212.34.2
isbot5.1.345.1.35
metascraper5.49.215.49.24
metascraper-description5.49.215.49.24
metascraper-image5.49.215.49.24
metascraper-title5.49.215.49.24
msw2.12.72.12.10
prisma7.3.07.4.0
tailwindcss4.1.184.2.0
vite-plugin-cjs-interop2.4.02.4.1

oauth/ subpackage:

PackageCurrentLatest
@epic-web/config1.21.01.24.0
prettier3.5.33.8.1
wrangler4.19.14.67.0
zod3.25.573.25.76 (within v3)

Medium (single major version bump)

One major version upgrade; check migration guides and changelogs.

PackageCurrentLatest
@faker-js/faker8.4.110.3.0
@octokit/plugin-throttling9.6.111.0.3
@octokit/rest20.1.222.0.1
@sentry/profiling-node9.47.110.39.0
@sentry/remix9.47.110.39.0
@sentry/vite-plugin3.6.14.9.1
@sindresorhus/slugify2.2.13.0.0
@testing-library/react15.0.716.3.2
@types/uuid9.0.810.0.0
@vitejs/plugin-react4.7.05.1.4
bcrypt5.1.16.0.0
chokidar3.6.05.0.0
close-with-grace1.3.02.4.0
concurrently8.2.29.2.1
cookie0.7.21.1.1
cross-env7.0.310.1.0
date-fns3.6.04.1.0
dotenv16.6.117.3.1
eslint9.39.210.0.0
express4.22.15.2.1
glob10.5.013.0.5
helmet7.2.08.1.0
jest-environment-jsdom29.7.030.2.0
jest-watch-typeahead2.2.23.0.1
lru-cache10.4.311.2.6
match-sorter6.4.08.2.0
p-limit5.0.07.3.0
p-queue8.1.19.1.0
path-to-regexp6.3.08.3.0
react-error-boundary4.1.26.1.1
react-lite-youtube-embed2.4.03.5.0
rimraf5.0.106.1.3
uuid9.0.113.0.0
vite-env-only2.4.13.0.3
vite-tsconfig-paths4.3.26.1.1

oauth/ subpackage:

PackageCurrentLatest
@cloudflare/workers-oauth-provider0.0.50.2.3
eslint9.28.010.0.0

Hard (multiple majors or framework-critical)

Multiple major versions or core framework pieces; may need patches.

PackageCurrentLatest
@remix-run/dev2.9.22.17.4
@remix-run/express2.9.22.17.4
@remix-run/node2.9.22.17.4
@remix-run/react2.9.22.17.4
@remix-run/router1.16.11.23.2
@remix-run/serve2.9.22.17.4
@remix-run/server-runtime2.9.22.17.4
@types/node24.10.925.3.0
@xstate/react3.2.26.0.0
vitest1.6.14.0.18
vite5.4.217.3.1
xstate4.38.35.28.0
zod3.25.764.3.6

Remix: There are patches in other/patches/ for @remix-run/react, @remix-run/router, and react-router-dom. Upgrading Remix will likely require re-checking or re-applying these patches.

Vite / Vitest: Vite 5 → 7 and Vitest 1 → 4 are large jumps. Expect config and plugin changes.

XState: xstate 4 → 5 and @xstate/react 3 → 6 involve major API changes.

Zod: 3 → 4 is a breaking change and affects many consumers (e.g. Conform, Remix).


Summary: 19 easy, 42 medium, 14 hard. Start with the easy group; for Remix, review the patches before upgrading.

A week or two ago I had Cursor update Tailwind from v3 to v4 (otherwise that would've showed up here too).

So next thing I did was fork the conversation and told it to update all the easy ones. That went without a hitch.

I then had it do the medium ones. This one did end up with a couple issues, but wasn't that bad. It handled most the breaking changes gracefully.

This only really works because I have some pretty good tests and documentation that I made when I was actively developing the project (with my bare hands, like some kind of caveman).

Major changes

I decided to do the major changes one at a time. I had it run the vite (v5 -> v7) and vitest (v1 -> v4) upgrades together. That went without a hitch.

Feeling pretty good about this, I had it run the zod upgrade. I've done the zod v4 upgrade before (with the Epic Stack and other projects based on it) so I knew that conform had a special export for zod v4, so I said:

Let's do zod now. Conform has a special export for zod 4 integration. Use that.

Everything was smooth.

Then I decided to make a new conversation and told it to upgrade xstate. I use xstate for the Call Kent Podcast in-browser recorder (my agent says there's about 200 lines of xstate related code in this project). So it's not a huge dep, but I remember when I originally wrote this and it was challenging.

I created a new conversation because it had told me that the @xstate/react v3 -> v6 upgrade was a major upgrade and I wanted to be sure to handle it carefully.

Please update xstate and @xstate/react. Before doing this, look up migration docs and follow those.

It searched the web and found migration docs, planned the migration, and executed the plan to perfection.

Double-Major changes

Ok, so first I have to say that migrating from Remix v2 to React Router v7 is not a true framework migration, but rather a dependency upgrade because Remix v2 was just a wrapper around React Router. In v7, the Remix team moved everything to React Router. They did the responsible thing by making "future flags" so you could incrementally adopt new features to avoid a big bang upgrade.

I had enabled none of those future flags.

I knew this one would be a pretty big upgrade, so I decided to use Cursor's new long-running background agent feature.

Here's the prompt I used:

Upgrade us from Remix v2 to React Router v7. Before doing this, look up relevant migration docs/upgrade guides. We have some remix-specific dependencies as well. Make sure their latest versions work with React Router. If they don't, find alternatives.

We have some patch files. These are to make it so we can add headers to remix fetchers and things. I don't think that feature will ever exist so I want you to delete those patch files and instead find an alternative solution (a simple fetch with a revalidation call should be sufficient, but double check my thinking on that).

It created a plan and I gave it a couple bits of feedback/answered some questions:

  • I want to use react-router-auto-routes, look up the docs for that. This will require moving files around a lot
  • REMIX_DEV_HTTP_ORIGIN is completely unnecessary in RR

Manual fetch, the reason we do this is to skip the unnecessary buffering of the request body in a server that can't do anything with this data anyway

This was an interesting decision because before I was using remix-flat-routes for filesystem routing. react-router-auto-routes is what the Epic Stack uses now (check the decision doc). Normally when upgrading a framework, you probably want to change as little as possible. But I figured the agent would figure it out. Living dangerously 😎

Anyway, that was it. Then I sent it off to do its thing and it did an awesome job. However, it did struggle with the routing convention change (predictable 😆).

So I sent this:

you need to fix the way our file structure is so it makes routing work. Right now with the way we have things in this branch, here's what I get if I run npx react-router routes: ... routes output ... If I checkout main and run npx remix routes I get: ... routes output ... You need to fixup our directory structure to make react-router-auto-routes match our original routing structure as closely as possible. The order can be different, and the file paths will definitely be different, but the basic structure must be almost identical. Lookup the react-router-auto-routes (what we want and have in this branch) docs and compare it to the remix-flat-routes docs (what we have currently in main).

The next time I tried it out, the routing worked perfectly (give the agent a way to check its work and it performs much better!).

Then I noticed that the agent had tried to keep changes minimal and I decided we could be more amitious:

Could you adopt the latest on how to handle types in Loaders, actions, components, etc based on the react router documentation? You can make a plan but don't wait for me to approve it. Just go for it. I'm going to sleep and want this all to be done when I wake. You got this!

Then I went to sleep. The agent kept running in the background for 21 minutes and finished that.

While I slept, it iterated a few times with Cursor BugBot. I have auto-fix enabled, so when BugBot finds issues, it automatically fires off an agent to fix the bug. It had managed things really well!

This morning, I pulled things down and played with stuff. It worked really well. Both BugBot and CodeRabbit had identified issues, so I kept the agents going to fix things as they were found. After a few more iterations, I merged it into main.

If you want to see the full migration diff, here’s the PR: kentcdodds.com#658.

Just amazing!

Thoughts

Life has gotten a little hectic lately:

Kent C. Dodds 🏹 avatar

Kent C. Dodds 🏹 @kentcdodds

I don't know about you, but recently my days have been extremely chaotic. I'm often working on several projects at once with sometimes a couple cloud agents running on each while guiding an agent more directly locally. Also handling email, 𝕏, and DMs between it all. It's not ...

29 158

My laptop is constantly pinging me with notifications from Cursor local and email notifications from Cursor Cloud Agents. I'm normally an inbox 0 and close the browser tab when I'm done with it kind of person, but it's honestly hard to keep track of everything. I have emails coming in from github PRs and I have so many tabs open for cloud agents and github PRs. Not to mention the 5+ cursor editors I have open locally for different projects. I'm all over the place. It's crazy. I love it 😂

Someone asked me how many prompts I send a day which I thought was a funny question because I don't think about it. But I'm pretty sure I send hundreds of prompts daily (depends on what you count as a prompt, but I'm including follow-up messages in conversations). I don't know, I wouldn't be terribly surprised to find out I'd sent 1000 prompts. I mean, just in this site, just this morning I have 25 agents that I triggered myself. Some are bigger, some are smaller. And I've got other projects going. Things are happening!

I've never had so much fun building stuff. At the same time, we're walking dangerous territory:

Kent C. Dodds 🏹 avatar

Kent C. Dodds 🏹 @kentcdodds

@johnlindquist YES This has become a problem for me. It's hard to take lunch breaks. It's hard to stop at the end of the day. It's hard to not pick up my phone during family time to just "send off a quick follow-up"

4 10

And

Kent C. Dodds 🏹 avatar

Kent C. Dodds 🏹 @kentcdodds

I am now always "in the middle of something" and it's very difficult to force myself to stop to do anything but send another prompt.

22 89

Finding balance is hard when the next big problem to be solved is just one more prompt away.

Hope you enjoyed reading this! And seriously, try out the new semantic search feature of the site! It was fun to build and I plan on teaching how to build something like this in the future (among other things), so sign up for my mailing list!

Cheers!