AI Development Tools

AI Development Tools

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:

Cursor analyzing package.json and running npm audit

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

Cursor recommending package-lock.json for Yarn project

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

Cursor's 4-step plan for dependency updates

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!

Cursor identifying node-sass as inactive and recommending sass

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!

Cursor continuing with npm instead of yarn

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:

Cursor handling legacy peer dependencies with --legacy-peer-deps

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

Cursor's summary of dependency updates

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's detailed summary of AI-guided dependency updates

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:

Cursor removing @tailwindcss/ui to resolve dependency conflicts

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

Cursor using --legacy-peer-deps flag to resolve complex dependency conflicts

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

Cursor updating React legacy dependencies

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.

Cursor identifying Node version incompatibility with react-router-dom

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

Cursor updating development 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 providing options for React 18 compatibility changes

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

Cursor encountering postcss compilation error

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.

Cursor making React 18 compatibility changes with approval options

And then Cursor gives me:

Cursor providing summary and next steps

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

Cursor updating postcss to ESM module syntax

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

Cursor running npm start after postcss fix

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:

Cursor fixing purgecss function 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:

Cursor resolving ajv dependency issues

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…

Cursor using --legacy-peer-deps for React version conflicts

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 addressing Node version conflicts and syntax errors

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 analyzing React import syntax errors Cursor's recommended changes for React imports Cursor's summary of React import 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!

Cursor addressing Spring Animation library issues Cursor's summary of Spring Animation changes

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 providing options for handling typed hooks and React Spring issues

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…

Cursor handling type safety with pragmatic solutions

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.

Cursor reverting to JSX syntax for 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:

Cursor fixing React Spring props with direct number values

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 preparing to push changes to Github

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

Cursor's final summary of changes Cursor's completion 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" />