Not that Create React App was ever bad. But when I started working with React back in 2019 I was not a fan of the idea that all the plumbing for your app would be completely hidden from view. I was coming from working with a production AngularJS front end, where I knew every inch of our Gulp build script, all the build configuration, and all the dependencies we used. It was essential to have this knowledge in order to enhance the build process or add new libraries in such a way as to not break anything.
But CRA takes a very different approach. You see none of that complexity. On the one hand it’s a relief since modern front end development is a minefield of OSS libraries, ever-changing language standards, and interdependent code that when combined is really hard to understand. Not having to worry about that has enormous mental benefits. On the other hand, CRA chooses a specific set of things to support. If you want to use something different, which is one of the primary selling points of the React universe, you are out of luck. You can break free of the CRA womb and use whatever tools you like via ejection, but as the wise man is oft quoted, ‘Stuff can break’.
But I didn’t care about that. I reasoned that having maximum flexibility is good, and if you are maintaining an app using a bunch of different tools you should know how those tools work. That way you can fix the engine when the car breaks down on the side of the road. And so with this sentiment I ejected all the CRA-based apps I created, both at my job and those that were personal projects. Part of me was worried about how to deal with maintaining the dependencies, but others had gone the same route and they seemed to have ways of handling it.
I recently had a change of heart and it started when CRA 5 was released. It included improvements to fast refresh, the latest version of Webpack, unpinned dependencies, etc. All good stuff. Around this time I had wanted to update a handful of personal React projects to the most current libraries. They were all ejected, and the the sheer number of dependencies to potentially have to update was more than a little daunting. Plus I wanted it done fast (and was lazy). So I thought about the main reasons I had ejected in the first place:
- I had wanted to use LESS, not SASS
- I did feel like knowing exactly what went into my build process was beneficial
I first started using LESS in 2016 and was happy with it, but in recent years I’ve had to use SASS at my job. And I’ve decided they aren’t really different enough for me to worry about. So reason number 1 doesn’t really apply any more. As for reason number 2, I finally realized what the CRA team was really getting at: they offer a curated set of libraries that you can assume are going to work fine together, and because there are so many nowadays, not having to deal with them all is clearly the better option. There will always be library updates, and having a known good set is a nice way of making sure you don’t get sucked into something that blows up your app.
So to do my personal upgrades I simply created new CRA projects in separate directories, copied over my source, made any necessary adjustments so they could build, then copied all that back over into the original repos. It was painless and allowed me to take advantage of the new hotness.
Update:
I didn’t learn this until summer of 2024, but it appears CRA essentially became deprecated in 2023. It is no longer being officially maintained in its current form, and is generally not recommended for new React-based projects. There are other options around so I’ll have to eventually pick one and switch to it.