Converting Next Pages to App Directory

Cover Image for Converting Next Pages to App Directory
Justin Bender
Justin Bender
Contents

Converting Next Pages to App Directory

The project that is going to be converted is a completed and working application. There is a high chance that it will have errors all over the place. This is just part of the struggle. Move a few pieces and see what errors come up. Move a few more until it seems to work. Possibly running tests along the way. It shouldn't be too much of a struggle until we get to the more complex pages. At first it will be simple(ish).

We will use the From Pages to App Vercel's NextJS guide. This will help us with the basics and find problems that we may not understand ourselves.

  • The app is already at version 13. So we will not be updating the version in a major way. We will just be bumping up to the latest version.
  • There is an updated:
    • Image component
    • Link component
    • Script component
    • Font optimization
  • Date fetching functions like getServerSideProps and getStaticProps have been replaced with a new API inside app. getStaticPaths has been replaced with generateStaticParams.

In the beginning we should note that the application needs a starting point. There will be two different places if you're in the app directory or the pages directory. The app directory has a layout and a page. The pages directory has a _app and a _document. For the root layout.

  • pages/404.js has been replaced with not-found.js.
  • pages/api/* currently remain inside the pages directory. What? Isn't there also an API route in the app directory? Yes, we have the ability to have both the API route in the pages and the app directory. It just changes the setup.

Let's take a look at the new setup for the layout.tsx:

export default function RootLayout({
  // Layouts must accept a children prop.
  // This will be populated with nested layouts or pages
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}
  • Why do we use normal html tags instead of imported next/document components? This is a question that we will hope to answer later.
  • App directory must include the layout. You must define the <html> and <body> tags since NextJS does not automatically create them.
  • Root layout does replace _app and _document.

You can manage the meta data in different layouts and pages with the Metadata import.

import { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: 'Home',
  description: 'Welcome to Next.js',
}

Migrating _document and _app

If you have the existing _app or _document file, you can copy the contents (e.g. global styles) to the root layout. The styles in the app/layout will not apply to the pages/*. You should keep the _app/_document while migrating to prevent routes breaking. Once fully migrated you can safely delete them.

Notes about this specific project. After moving over the first component

  • With styled components we will need to use client components. It's not available in server components as of the writing of this post.
  • The useRouter() hook will have to be imported from next/navigation.

What is the difference between server and client components?

  • Client components are all of the react that we are used to in the past.
  • Server components are for fetching data and sending some data back to the server.

💬 Where should the client component be. Should it be at a top level. Or should we keep as many as server components as possible. Can we keep layering these components. Client and server on top of each other without any kickback? Or do we run into problems?

Creating and moving over our first components

  • Inside of the app directory we will include a opengraph-image.alt.txt and a opengraph-image.png that should get added as our tags for social medias at the top of all pages. Unless we chose to start editing the metadata using the next component for a more dynamic approach.

In the process of moving over the _app/_document over to layout. The first difference I notice is the fact that we don't import the Head, HTML, Main, and NextScript. I won't be including NextScript for this. Not 100% sure if we need it or why. We will keep the Script from next/script. That will still be used with our strategy="afterInteractive" property.

Most of the file is just copy and pasted over. When the project is run. It was throwing errors about how the useRouter() needed to be imported from next/navigation now. Which is fine. We just went to the imported components that required those. Switched them over and they "seemed" to work fine again. Or at least the transpiler did not keep yelling.

  • What do we do about importing the fonts from google?
import { Inconsolata, Roboto } from 'next/font/google';


const inconsolata = Inconsolata({
  subsets: ['latin'],
  weight: ['400', '700'],
});

const roboto = Roboto({
  subsets: ['latin'],
  weight: ['400', '700'],
  display: 'optional',
  style: ['normal','italic']
});

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={`${inconsolata.className} ${roboto.className}`}>
      <head>
    </head>
  • We will import Roboto and Inconsolata with some specific settings. Which will them be added to the className so to fonts can be used across the whole project.

💬 When you're using providers they will have to be on the client side.

Adding to the head of the page

In the old format we would use the Head component and write inside of those. Which isn't how we do that in the app component. We will use the Metadata import from next.

import { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: 'My Page Title',
}
 
export default function Page() {
  return '...'
}

🛑 At this point the most basic setup is moved over. We will have the beginning of the project moved over. This will allow for use to start moving over each page until we have them all over inside of the app directory. After we move everything over to the app directory. We will deleted the pages directory.

Moving over pages routes into the app directory

  • What changes when we use the app directory?

We use folders and inside of those folders. There are files that have specific uses. The main file we will use is page.tsx. This will be the main content of the page that we will be bringing over.

  • Let's bring over the login and the register components. This went relatively well so far. Nothing special happened. Had to change a few next/navigation useRouter() imports.

Most of the files move over really easily. If there are hooks involved we will make sure that use client is at the top of the page. To allow for normal client components. We can get most pages to move over without a problem.

  • When you get query params. That style changes in Next 13 app directory to useSearchParams() where you can use it like.
const searchParams = useSearchParams();
const mode = searchParams?.get('mode') as mode;
const oobCode = searchParams?.get('oobCode') as string;