"How are you building React applications?" This is a question that often comes up with application engineers when they are starting new projects. People tend to gravitate towards what they know, but is that the correct choice? And, with so many options today, how do you know what the right choice is?
While many of us started our React journeys by using the Create React App tool, it's best days are behind it. It's time to evaluate new tools. This blog post covers why it's time to move beyond Create React App and introduces you to new tools, including Next.js and Vite, that can help you build React applications better.
Limitations of Create React App
Create React App was designed with one purpose in mind: To provide an accessible way for anyone with a terminal to create a React application. The open-source tool was ideal for learning or becoming familiar with React.
The benefit to this tool was that developers could begin developing straight away without the need to learn complex build tooling such as webpack or set up a slew of tools such as Babel, ESlint, or TypeScript.
"[Create React App] was intentionally minimal and limited in scope (no configuration, no plugin system) for two reasons. One reason was that, the more feature-rich it is, the harder upgrades will be. The other reason was, I knew that React itself will take a vast majority of our time, and I won't be able to dedicate more than a few weeks sporadically to CRA every now and then."
~ Create React App Co-Creator
Due to this unnecessary need to learn tooling, developers skipped learning the underlying tools their applications were so heavily built upon, causing them to become reliant on this no-configuration style approach. This issue becomes apparent once teams need to break out of the safety net CRA provides.
The CRA developers knew developers would eventually need to enable features beyond the feature set provided, so they created an eject button for teams. The eject feature removed the dependency on react-scripts
and copied a snapshot, in-time version of the configuration files used in the project. The snapshot version of these complex configuration files coupled with a lack of individual knowledge about the tooling caused projects to either stop their upgrades or introduce messy updates when needed. CRA even suggests forking react-scripts
instead of ejecting for somewhat easier updates, but this also can be a daunting task depending on your use case or familiarity with the tooling.
So, instead of entirely managing these configuration files, teams took to utilizing tools such as Craco to override configurations. These tools also come with their limitations: they were not updated as quickly as CRA, so there was always a lag in implementing new features, and they added an extra layer of complexity to existing tools through overrides and additional tools.
"Realistically, CRA is inherently very limited. It does not follow best practices for performance because it produces client-side only apps. This means it doesn't benefit from optimizations that are commonplace today with other frameworks, such as static generation or server-side rendering. Unless there is a drastic redesign, it won't benefit from future-facing features like Server Components. So if you care about delivering the best user experience, I don't think CRA is the right tool in the first place. It has its use cases, but many other tools now exist that do this job better. CRA still works great for the getting started use case, but you shouldn't see it as the best React app setup. It's not, and isn't meant to be." ~ Create React App Co-Creator
Still not convinced to move on from Create React App? Even the React Docs no longer recommend Create React App for bootstrapping a new project.
Next.js as an alternative to Create React App
Next.js, much like Create React App, is a no/low configuration framework to quickly get a project up and running with React. Next.js does offer a greater feature set and the ability to natively override build tool configurations based on your needs.
Benefits of Next.js
React natively renders content in the browser through client-side rendering. This means the end user downloads all the assets and code necessary for the browser itself to convert the React code to a native DOM output for the browser to display. Next.js, on the other hand, allows the use of both client-side rendering as well as server-side rendering, which means the server interprets the code and produces the DOM elements required for the browser to display.
By using server-side rendering (SSR), the server is able to optimize the delivery of JavaScript, CSS, and other asset chunks in preparation for the browser to display results in a faster initial load time. I won't spend time diving into the nuances of this as many other individuals have already done so. If you are interested, check out this article showcasing the comparison of CRA vs Next.js performance differences.
In additional to SSR, Next.js provides additional options for data fetching, providing alternative options for rendering based on the application's use case.
Next.js provides native TypeScript support requiring a zero-configuration approach to using TypeScript in your projects. Next.js also includes a built in router without the need to include additional libraries such as React Router. All-in-all, there is a long list of features provided by Next.js such as:
- image and font optimization
- built-in CSS support
- build caching
- linter setup
- page and layout support
Be sure to check out the Next.js documentation page to read more.
Now, you may be thinking to yourself: "Next.js doesn't seem to solve the problem of the development team not learning the toolchain the application is built on." And, you are correct.
Even though Next.js provides additional configuration options and the ability to override most of the tooling it uses, it still masks the complexity of the underlying toolchain. In many cases, this is acceptable because you can access tools to modify, if necessary, while not recreating the wheel every time you want to do something relatively basic.
Downsides of Next.js
- Next.js has a relatively poor plugin ecosystem
- Customizing routing can be cumbersome
- Extremely opinionated (could also be a benefit)
Roll your own with Vite
What about rolling your own? Most people that have only ever used CRA, Next.js, or similar tools will think that seems like a lot of work. In the past, it usually did require quite a bit of knowledge about webpack, so you aren't wrong. But tooling has come a long way, and tools like Parcel, NX, and Razzle have simplified the process. Even more recently, Vite has gained an ever-increasing market share.
"Why?" you might ask. Vite is built on top of esbuild, a Go-based bundler for the web that is 10-100x faster than other bundlers such as webpack. Vite is also platform-agnostic, so you can learn the tool and use it for many applications.
Vite has a great plugin ecosystem because it leverages the same plugin interface as Rollup, meaning most Rollup plugins are also compatible with Vite. The Vite guide offers more reasons for why you might want to check out Vite.
It also has a nice tool create-vite which aids in the creation of a a project using a set of predefined templates much like CRA does. As of this writing, currently supported templates are:
- vanilla
- vanilla-ts
- vue
- vue-ts
- react
- react-ts
- react-swc
- react-swc-ts
- preact
- preact-ts
- lit
- lit-ts
- svelte
- svelte-ts
Vite isn't quite rolling your own, but is getting much closer to the toolchain than the previous options.
Other alternatives?
Obviously, there are tons of other options available besides the ones listed above, but I wanted to showcase a natural progression developers can take within the React ecosystem. Below are some links to additional popular options other developers use for building and bundling their React applications:
- Parcel: Prides themselves on the zero-configuration approach.
- Nx: Most notably known as a monorepo tool set with a vast plugin ecosystem.
- Razzle: I've never used it personally, but based on what I can tell it seems to be an attempt to enhance the Create React App concept, enabling CSR/SSR while also working well with libraries other than React.
- Gatsby: Excels in static site generation and uses GraphQL for data management.
What's next?
It is great to see so many options available for both new and old developers. It seems as though every few months, another player emerges in the space looking to challenge and disrupt the React ecosystem. Because of this ever-changing landscape, it's best not to over-invest time and resources on one tool, but instead lean on the experts in the communities such as Next, Parcel etc. for a somewhat-opinionated approach to solving similar problems.
Looking forward, some other projects that I find have some really great potential in the approach they take to simplify the toolbox are Remix and Astro.
- Remix: is a web framework built with web standards and progressive enhancement in mind. Check out their project page for more information.
- Astro: is a web framework that encourages the use of the island architecture and more checkout their project page for more information.