10 October 2023
Selecting the Right Tech Stack for Large-scale React.js Project

React

Starting a big project? Picking the right tools can make or break it. Next.js might just be what you're looking for. It's more than just its impressive 113k+ stars on GitHub. With 5 million weekly downloads and being the choice for giants in the software world, it's a testament to its reliability and efficiency. So why do big names trust it?
Bartłomiej Stefański
Bartłomiej Stefański
Head of Engineering
Selecting the Right Tech Stack for Large-scale React.js Project

Next.js as an Enterprise framework

Starting a big project? Picking the right tools can make or break it. Next.js might just be what you're looking for. It's more than just its impressive 113k+ stars on GitHub. With 5 million weekly downloads and being the choice for giants in the software world, it's a testament to its reliability and efficiency. So why do big names trust it?


  • Scalable Design: Next.js is engineered to adapt. Whether you're building for a niche audience or anticipating significant traffic spikes, its inherent design and serverless deployment options ensure reliability.
  • Performance Tools: With Next.js, performance isn’t just an afterthought; it’s baked in. Not only does it bring different types of rendering to the table, but it also offers a variety of modules to streamline performance further. The framework intelligently picks the right defaults and provides capabilities like selective and progressive hydration — things many other frameworks can’t do yet.
  • Developer Experience: Next.js really cares about making devs happy. They’ve got their own speedy Rust compiler and they’re always finding ways to cut down on loading and building times. It’s all about making your coding life easier.
  • Maturity: Next.js has been around since 2016. In the fast-paced world of frontend tech, that's a good chunk of time! It's not just another fleeting trend - it's stood the test of time and evolved, ensuring you're building on a solid foundation.
  • Community: The Next.js community is massive. Dive into any tech forum, Discord channel, Github Discussions or blog, and you'll find a mountain of solutions or things you didn’t know. It's not just about the size, but the enthusiasm. With this many devs loving and talking about it, you're never far from an answer or a fresh perspective.


Navigating such a huge ecosystem can feel like wandering in a maze. Ever felt overwhelmed picking tools and hoping they won't let the team down? We've been there. That's why we created the next-enterprise template. This post will walk you through each decision we made for this project. We want you to understand our thought process and why we believe it is a great toolset.

Styling


Tailwind CSS and CVA

Think of Tailwind like a giant box of LEGO — you dump it all out on the floor and build what you want. When you're done, you put all the pieces you didn’t use back into the box. It’s utility-first CSS at its best, letting you cobble together styles on-the-fly. No more navigating through unused CSS or wondering which style does what. It’s straight-up efficient, for a user and a programmer.


It’s also zero-runtime, which means that it will work in any environment you set it up with. It natively works well with Next.js, both in Pages Router and App Router.


One thing that Tailwind is lacking compared to other solutions is the variants system. That’s why we decided to add the CVA library to the boilerplate. It provides an easy to use API for creating component variants.

Radix UI

Radix is an open-source UI component library, emphasizing accessibility and developer experience. The beauty of Radix is its headless approach, allowing you to couple it with any styling method.

Radix Ui

Testing

When tackling big projects, you'll often bump into the need for three main types of tests:


  1. Integration tests - They focus on the logic of your “smart components”. They're tricky to maintain, but we can't ignore 'em.
  2. Unit tests - Here, we're looking at individual pieces of your code, especially the ones that aren’t all tangled up with libraries like React. They usually test some API abstractions, parsers, helper or utility functions.
  3. E2E (End-to-End) tests - These are the big-picture tests for your whole app. Writing them is super easy. But they can be slow, and sometimes you've got to tweak your app just to test certain things.
Playwright

We’re not here to debate which testing method is king or if you should use all of them. But if you're diving into a big project, it's a good idea to be ready for all three. So, we've added some tools to help:


  • Playwright for E2E tests. It's a notch above others like Cypress or TestCafe. It's got a useful interface and makes life easier for developers.
  • React Testing Library for testing JSX components. If Enzyme's on your mind, that’s also an option, but not a good one. It's kind of falling behind the curve by not supporting the newest React features and is only maintained by one developer. If you're curious about why Enzyme might not be the way to go, here's an insightful read: Goodbye Enzyme
  • Jest as our test runner. Vitest is another option, but Jest aligns better with our setup and has solid integration with Next.js. Adding to that, Vitest would mean installing Vite.
  • Storybook - not only as a tool for manual testing by QA/UI teams, but also for automated Smoke tests that you usually have to do manually - legendary “should not explode” test.

Type Safety

When you're part of a large team, type safety becomes crucial. It not only helps avoid errors but also ensures that colleagues don't misuse your internal API, whether that's a facade, abstraction, or something else.


Getting TypeScript on board is a commendable start, but it's just the tip of the iceberg. Within the tsconfig.json, there are a lot of settings aimed at type safety. We've chosen the options that will be perfect for most projects.


On top of that, we've integrated a tool named ts-reset. Think of it as the "CSS Reset" for TypeScript. It tweaks typing definitions of certain internal node.js or browser modules. For instance, it modifies functions like JSON.parse or fetch.json() to return unknown instead of the usual and disliked any.


We've had times when we messed up with environment variables or forgot to update them everywhere. So, we brought in the @t3-env library. It checks environment variables during the build or in the runtime. And, it offers a reliable and well-typed single source of truth for your environment variables.

Code

1export const env = createEnv({ server: { // Server variables SECRET_KEY: z.string(), }, client: { // Client variables API_URL: z.string().url(), }, runtimeEnv: { // Assign runtime variables SECRET_KEY: process.env.SECRET_KEY, API_URL: process.env.NEXT_PUBLIC_API_URL, }, })
2

Code quality

Code quality is one of those endless debates. Every seasoned developer might have their unique twist on writing code and what makes it clear. However, there are certain practices and tools that the majority can nod to, including:


  • Putting imports in a logical order at the beginning of a file.
  • Tailoring ESLint rules to what the team finds most valuable.
  • Using conventional commits to speed up releases and have a tidy GIT history
  • Employing Prettier for a neat code format.
  • Using absolute imports to keep files easy to read.
Code quality

Another tool for more complex projects is the "coupling and cohesion graph". This script is a game changer if you want to architect your app in a more maintainable way. You will find it helpful even if you want to just streamline the build times or performance of the application.

Observability

Once the application is live, it's vital to monitor any errors or warnings that users might encounter. After all, no app is flawless, and users will inevitably face issues, be it a significant glitch in a React component or an oversight like missing a polyfill for Safari users. In such instances, logs and tracking are a must.


We believe in flexibility, so rather than tying you down to a specific product, we've implemented a universal library called OpenTelemetry. This lets you pair it with any provider of your choice, whether that's Sentry, NewRelic, or another.

CI/CD pipelines

A swift and dependable CI/CD process that doesn't hiccup every other day or drag on for hours is crucial. Here's why:


  • It helps you roll out updates quicker.
  • It boosts developer productivity.
  • It ensures top-notch product quality.


So, we've added a few Github Actions and tools to get this right:


  • Automatic deployment to Vercel. Just a click and you can deploy your instance right here. Plus, you get preview branches for every commit you push.
  • Check Action - It lints your code, runs unit and integration tests, validates types, transpiles the code, and wraps up with a formatting check.
  • Bundle Analyzer - Keeps an eye on your bundle size changes for each PR. So, any hefty library additions won't slip past (moment.js đź‘€).
  • AI CodeReview - Think of this as a sharper alternative to tools like SonarQube.

Summing up

In short, for anyone tackling major React.js projects, Next.js provides more than just a framework - it's an entire toolkit. And with the next-enterprise template, starting up becomes even smoother. Given its constant updates and strong community backing, Next.js stands out as a solid choice for ambitious projects. If you're looking for reliability and efficiency, Next.js is a smart pick.

blazity comet
Get a quote
Empower your vision with us today
The contact information is only used to process your request. By clicking send, you agree to allow us to store information in order to process your request.