AI Development Tools

🛠️ How We Are Using AI Development Tools Here at Bluesunrise
The Bluesunrise Team is embracing AI-enhanced development tools in our every day work. For the most part, this has been a positive experience with productivity gains and improved code quality. Here are the tools we are using:
🛠️ Updating a Four Year Old React App with Cursor
In this blog, we dive into our experiences with Cursor, the AI enhanced Code editor, demonstrating positive (and negative) takeaways from our effort to upgrade a four year old React project’s dependencies to the latest versions. In the past, we have had project leads, working with Renovate and release notes to maintain dependency updates. This project that we will be looking at went dormant for four years, then suddenly came back with new customer requirements. Instead of using Rennovate and an experienced developer, we asked Cursor to update the dependencies. Here is how it went…
First, we ask Cursor to create a branch and update all dependencies on that branch, and give Cursor a hint that the project has not been updated in 4 years. It analyzes the package.json, sees its a React program with TypeScript and Tailwind CSS. It then says it will be careful not to break any dependencies and runs npm audit. I don’t know why it doesn’t recommend yarn audit
over npm audit
- this project is built by Yarn, not NPM. This leads to more assumptions by Cursor that the project is NPM, ignoring yarn:

Like when Cursor recommends adding a package-lock.json to a Yarn project instead of using the existing yarn.lock
:

Cursor makes an organized plan of action, complete with the 4 steps of its plan. But again we get npm install
instead of yarn

We run into a problem updating the dependencies. Cursor figures out that node-sass
is no longer active, and that we should switch over to the new saas
dependency. Nice job Cursor!

At this point I should have reminded Cursor that we using Yarn and not NPM. But I didn’t. Will we just carry on the Cursor’s switch over to NPM. Cursor is doing such a good job, why complain!

It then goes on to uninstall node-saas
and install saas
, update the React dependencies without issue. React is a fast moving project. Now we start to pay the price for not updating the app. We run into conflicts with legacy peer dependencies. Cursor knows about legacy peer dependencies, and diligently applies the --legacy-peer-deps
option to npm install
and tries again:

All the legacy peer dependencies are updated. Cursor gives us a very nice summary of what it did:

Cursor is on a roll now! Its giving me summaries of all the AI-guided dependency updates it has applied. Quite a few, very cool!

Cursor runs into a dependency conflict and gets conflicting peer dependencies on compile. It realizes this, and says “Lets handle this in a more structured way”. First it removes @tailwindcss/ui:

We get more complex dependency conflicts. Cursor tries a different approach, knowing to leverage the —legacy-peer-deps flag again:

After fixing tailwind legacy dependencies, it follows down the logical path and goes after react legacy dependencies next:

In doing so, Cursor stumbles onto a react-router-dom dependency requirement on Node which is incompatible with this project’s version of Node. Cursor has excellent knowledge of supported Node engines per dep.

Our React deps are up-to-date. Now that the legacy deps are fixed, Cursor next determines to fix the dev dependencies:

That goes well. Cursor kindly summarizes what it has done thus far, and gives me 3 options on how to proceed. I choose to run (1 and 2) to run the development server and make changes for React 18 compatibility:

Cursor runs npm start
and hits a postcss
compilation problem immediately:

Next comes React 18 compatibility changes. At this point, Cursor boldly starts editing code. Note how it explains how it is searching with comments containing the grep search commands. Cursor knows that the main entry point code has changed in React 18. It makes the change. Cursor knows that React 18 does better with strict mode, and adds the import. Note the “Accept All” button at the bottom of the screenshot. Cursor will not make changes without my approval. I can also reject the changes.

And then Cursor gives me:
- a summary of what it has done
- the choice to review changes
- the option to start the dev server

Oops we hit a bump again with postcss
failing. No worries. Cursor is on it, updating to ESM module syntax:

Now that the postcss
error is fixed, we try npm start
again:

Another compile error. purgecss is not a function
. No worries. Cursor sees the error and recommends a code change. I accept this recommendation and we progress to the next error:

Yet another error this time with ajv/dist/compile/codegen
. Honestly, I am not familiar with ajv
. But Cursor is! It recommended some dependency magic and we are on to the next issue:

More React version dependency conflicts. Cursor brings in its old, trustworthy --legacy-peer-deps
option to npm install
and off we go on another build…

Node version conflicts. I am not sure how we got into this Node version problem. Maybe its my fault, I should have been more clear in my prompt than just saying “update to the latest and greatest”. Cursor, like any good programmer, recommends clearing the cache. I do that, rerun npm install
and we get syntax errors. I assume these errors are due to APIs changing over time:

Cursor thinks it knows why we are getting syntax errors. It summarizes its analysis in the list of 4 main issues below. These changes take some pretty deep analysis of the React imports. I like how it introduces an interface to carefully add the children property. Here is the whole diff of what it recommends along with the summary of changes.



Cursor asks me to continue with these fixes. I say go ahead. We get more errors (Im not including the errors). The next problem Cursor runs into is with the Spring Animation library. More refactoring and another summary. I love these summaries!


We get further down the compile path but we are still snagged on typed hooks and the React Spring library state. At this point Cursor takes a step back and ponders over the fact that we’ve made 3 changes without success. I am given 4 choices on how to continue. I choose option 2, keep the current implementation and continue:

Cursor makes several more changes. It shows strong typing knowledge, knowing that casting as any
is not ideal for type safety, but Cursor justifies still casting to any as a pragmatic solution to a complex typing issue. Interesting choice…

We are now compiling but getting a runtime error. Cursor recommends to revert back to using JSX syntax, and abandons the nasty cast claiming proper type safety.

Nope. More runtime errors. Cursor thinks it sees the problem now. It wants to introduce variables for the React Spring props. It backs this change saying we are now passing a number value directly instead of a percentage. Seems logical, although I am not familiar with React Spring (I wasn’t the author of this original code). Here is the recommended change which I accept:

That seemed to fix it. I celebrate and tell Cursor we are going out for beers! But first, I ask Cursor to push the changes up to Github:

Cursor knows when its done. It gives me a summary:


All set. I ask Cursor to request a review from the original author. I happily think I’ve succeeded. However, the next day, the author of the code contacts me. He says “it doesn’t work!”. And he provides a fix. I go to review the running app, and he is correct. The React Spring animation was failing miserably. Cursor, how did we miss that? I then apply the author’s fix, and the app is now correctly animating.
The author tells me the fix took him maybe 15 minutes. Im not going to be judgemental. Cursor did a very impressive job refactoring and analyzing the problem. Following its analysis and summaries sometimes left me in awe. I think that the ultimate solution would’ve been to have this tool in the hands of the original author. But sometimes that is not possible. In retrospect, maybe I was a bit lazy and became dependent on Cursor instead of analyzing the code with Cursor. I apologize that the blog got to be so long, but it was an interesting experience for me and I thought others might learn from it.
One final bonus from Cursor
I don’t know about you, but I don’t like typing in alt
attributes for images. It is time consuming and difficult to summarize. Well, Cursor can do that for you. Just select your context
, usually the file you want to global replace the alt tags on, and prompt cursor to
“on this current page only, for all images, replace alt attribute values with text from the image”
And off it goes, I now generated alt tags for all my images. Don’t forget to accept the changes. For example:
<img src="/images/cursor/cursor_031.png" alt="Cursor fixing React Spring props with direct number values" width="500px" style="margin-left: 100px" />
<img src="/images/cursor/cursor_026.png" alt="Cursor addressing Spring Animation library issues" width="500px" style="margin-left: 100px" />
<img src="/images/cursor/cursor_021.png" alt="Cursor using --legacy-peer-deps for React version conflicts" width="500px" style="margin-left: 100px" />