undo
Go Beyond the Code
arrow_forward_ios

Migrating classical React applications to Next.js

March 28, 2024

Introduction 

Next.js is a frontend framework built on the top of React. It has many features that allow to fine-tune and optimize web applications and simplify their development, including Client-Side (CSR) and Server-side Rendering (SSR) and improve development experience with fast hot reloading.

At Ensolvers we maintain and continue working in traditional React applications that have been in  production for several years and conceived with more classical setups like Create React App. However, some time ago we decided to start migrating all these applications to Next.js to start using its features.


Technical implications

As aforementioned, Next.js offers various interesting features in comparison to using a raw React setup. However, migrating an existing client-side app without deep changes involves a sequence of steps. The first phase we describe in this document is to migrate the apps to a Next.js setup using 100% Static Site Generation (SSG), so we have (1) Next.js available to start making use of their features and (2) use their mature bundler/compiler and dev environments.

The first step is to create an empty Next.js app 

At this point, Next.js requests a set of configuration parameters. In our case, we just keep those that will match the current project configuration - preserving TypeScript and maintaining the /src folder.

In our case, to preserve the same behaviour that is present in SPAs, we wanted to maintain React Router as the main router framework. This was needed since migrating to Next.js Router would have implied a lot of changes in the structure of the code and navigation framework. The only side-effect we've found when doing that is that in the dev environment, since Next.js runs its own server, routes on the "client" React app (i.e., React Router Routes) return a 404 since, effectively, those pages don't exist in the Next.js navigation realm but are correctly interpreted and processed on the client-side. To solve this issue we needed to define a middleware.ts file in our project root folder with the code below, which basically does an internal rewriting of all requests so the content of the index (/) page of the repo is returned in all cases (except for some cases which are defined as exceptions). As a result, the index page will load the React client-side app and then the client-side Router will take care of rendering the right screen.

Next step is to start moving all our previous code to the `src/` folder. In this case, we have to consider an important fact: by default, Next.js tries to apply server-side rendering. However, in our app, since we were based on a traditional React setup (which is designed to run on the client-side by default) there might be some unsupported behaviour in the components of the app. So, we need to add the `use client` directive to individual components and on the root level too.

Then the next step is to run the application in dev and check if everything looks good

After that, we need to ensure that we are generating a bundle that can run without a server and just run in a CDN as a SPA. Thus, we need to add the following to the next.config.js file

Since our previous CI/CD pipeline config generated all the output into the `dist` folder, we define the `export` script into the `package.json` file as following

And finally, we tweak the building commands to be as following to generate the static site

Conclusion

In this article we explained a simple, step-by-step guide to migrate a classic SPA written in React to Next.js. Despite the advantages of doing that are limited due to CSR (and SSG), performing this migration opens the door to start using features that Next.js provides in an iterative way in already migrated projects.

Cristian Ferretti
Software Engineer & Solver

Start Your Digital Journey Now!

Which capabilities are you interested in?
You may select more than one.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.