DEV Community

loading...
Cover image for My experience migrating projects to Next.js

My experience migrating projects to Next.js

rinatrezyapov profile image Rinat Rezyapov Updated on ・4 min read

Official documentation about migration to Next.js is pretty comprehensive and guides you through almost all the common steps that you need to take in the process.

Still, there could be some use cases specific only to your React.js application.

Pages folder

Next.js bases its file system routing on pages folder. This is a pretty neat approach but comes with some limitations. The problem with classic React.js applications is that some of them might not even have pages folder or have it deeply nested in the folder structure.

root
|
└───src
│   │
│   └───app
│       │   App.tsx
│       │   ...
|       └───pages
│   
└───template
│   │
│   └───components
│   └───colors
Enter fullscreen mode Exit fullscreen mode

More to that - Next.js allows only two locations of pages folder:

  • root/pages
  • root/src/pages

So keep in mind that you'll have to do some folder structure refactoring before moving to Next.js.

Components that use Web API

You probably know that you can't use window object server-side and you need to always check whether window is defined before accessing it.

For components that extensively use Web API (charts, animations) and too complex to refactor, it's easier to dynamically import the whole component from the parent component.

import dynamic from 'next/dynamic';

const ChartsComponent = dynamic(
  async () => dynamic(() import('app/components/ChartsComponent')),
  { ssr: false },
)
Enter fullscreen mode Exit fullscreen mode

Next Router isReady

Sometimes a user is redirected to your React.js application from other services with some information in query parameters. It could be an email about registration confirmation with confirmation token: https://yourReactApp.com/token or redirection from a OAuth provider.
In such cases you usually catch these query parameters using window.location.search and then process them.
I noticed that when I moved my application to Next.js these query parameters didn't appear in Next's router at first render and only on the second render I could see them in router.query. This behaviour broke my authentication process. Turned out that this is because Next's router fields are updated server-side first and only then client-side. To skip the first update with the empty query you have to use router.isReady field in useEffect hook as a second argument:

import { useRouter } from 'next/router';

const RedirectsCatcherComponent = () => {
  const router = useRouter();
  useEffect((() => {
    if (router.query.token) {
      proceedAuthentication(router.query.token);
    }
  }), [router.isReady])
}
Enter fullscreen mode Exit fullscreen mode

Dockerfile

If you use Docker containers in your infrastructure you could use the example of Dockerfile in the official documentation or if you use npm:

FROM node:alpine AS builder

WORKDIR /usr/src/app

COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
RUN npm install --production

USER node

FROM node:alpine
WORKDIR /usr/src/app
COPY --from=builder /usr/src/app .
EXPOSE 3000

ENV NODE_OPTIONS=--max_old_space_size=1024

CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode

Basically what it does here is it builds static assets using production and dev dependencies and then install only production dependencies that needed to start Next.js server.

Notice ENV NODE_OPTIONS=--max_old_space_size=1024 here. If your Docker container resources are limited, the build process sometimes might crash with the error Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory. This environment variable solves the problem. Just make sure that is slightly lower value is set than Docker container memory limit value.

You are not static anymore

With great power comes great responsibility

I'm sure you decided to use Next.js mainly because you wanted to improve the performance of your React.js application with server-side rendering.
One thing to consider is that you as a frontend developer will be responsible for running Node.js server that will serve static assets. Everything that is running tends to crash, so bear in mind that you will need to consider some kind of failover solution. It could be pm2 or Nomad or even multiple Docker containers in nginx upstream configuration.

Can Next.js replace nginx?

It depends on what kind of job your nginx performs. If it's only modifying headers then Next.js can do it also. It even can set security headers with the help of a third party library.
For some more advanced use cases, such as determining the real user's IP address you would probably need to use custom Next.js server.

Authentication

As I said before, if you are using Next.js you are probably going to use server-side rendering.
A typical client-side React.js application usually uses JWT tokens for authentication and stores them in a browser's storage.
As you may also know browser's storage is not available server-side and you won't be able to get tokens and use them to make authenticated requests to the backend and render authenticated pages server-side.
If it's your case then you need to think about storing authentication tokens in cookies. After that you will be able to get authentication tokens in req.headers.cookie server-side.

async function getServerSideProps(context) {
  if (req.headers.cookie) {
    const token = getToken(req.headers.cookie);
    // make requests
  }
}
Enter fullscreen mode Exit fullscreen mode

If you need to perform authentication client-side you just retrieve the cookies from the browser.

The process of moving from browser's storage to cookies in terms of storing tokens is usually pretty complex, especially if you are using an OAuth protocol.
If you store tokens client-side then you probably have a mechanism that periodically refreshes these tokens and checks if they are valid. You will need to move this mechanism to the backend side since the backend will be responsible for handling tokens and putting them in cookies. If you are using an OAuth provider, it's even harder. So think about this step in advance.

For now, that's it. From my experience, migrating to Next.js most of the time was a surprisingly positive experience, so if you planned to move to Next.js - make preparations and do it now!

Discussion (9)

Collapse
kalashin1 profile image
Kinanee Samson

I really like how next takes care of routing for you.. I always hated having to setup routing manually

Collapse
rinatrezyapov profile image
Rinat Rezyapov Author

Agree. Setting up routes was the second thing that I hated, first was setting up Redux🙂

Collapse
kalashin1 profile image
Kinanee Samson

No, not Redux.. Gosh i don't use Redux at all

Collapse
paras594 profile image
Paras 🧙‍♂️

nice overview. Only the auth part is a bit difficult.

Collapse
rinatrezyapov profile image
Rinat Rezyapov Author

Hi Paras! Glad you liked it!
Yes, authentication part is a little bit clumsy, that's because it depends on what authentication scheme the project that you want to migrate to Next.js used.
I believe this is a more detailed overview stackoverflow.com/a/61220336/6542218
Hope it will help!

Collapse
paras594 profile image
Paras 🧙‍♂️

Woww...Thanks for the great reference !!...It is helpful :)

Collapse
codbugs profile image
Coding Bugs

Nice article. It list a lot of relevant things to take into account in migrations to next.js

Collapse
rinatrezyapov profile image
Rinat Rezyapov Author

Glad you liked it!

Collapse
dastasoft profile image
dastasoft

The routing is very convenient, for that and being able to choose between static and dynamic I'm going with Next for all side projects now.

Forem Open with the Forem app