App Routing with NextJS

"I'm building a blog website and I'm having a routing issue in Next.js. I have a homepage, a blog page (bai-viet), and individual blog posts, and the directory structure is as follows:

├ app
├─ layout.tsx
├─ page.tsx
├─ [uid]
│   └─ page.tsx
├─ bai-viet
       └─ [uid]
│          ├─ page.tsx
│   ├    page.tsx
│  ........

The problem I'm facing is that when navigating to '/bai-viet', instead of fetching data from app/bai-viet/page.tsx, it's fetching data from app/[uid]/page.tsx.

In my prismicio.ts file, I've configured the routes as follows:

const routes: prismic.ClientConfig['routes'] = [
{ type: 'page', path: '/', uid: 'home' },
{ type: 'page', path: '/:uid' },
{ type. 'page', path: '/bai-viet', uid: 'bai-viet' },
{ type: 'article_post', path: '/bai-viet/:uid' },
{ type: 'settings', path: '/' },
{ type: 'navigation', path: '/' }
]

This error only occurs after executing the 'npm run build' script on local or deployed on Vercel. The local development environment working correctly.

I follow this github repo, add new page.tsx file in bai-viet folder, define new route in prismicio.ts
{ type. 'page', path: '/bai-viet', uid: 'bai-viet' },

In admin dasboard Prismicio, I create a new page with UID == 'bai-viet'

I think UID == 'bai-viet' in app/[uid]/page.tsx conflict with app/bai-viet/page.tsx file, because in app/bai-viet/page.tsx file, I query data from uid == 'bai-viet'

export default async function ArticlePage() {
  const client = createClient()
  const page = await client.getByUID('page', 'bai-viet').catch(() => notFound())

  const posts = await client.getAllByType('article_post', {
    orderings: [{ field: 'my.article_post.publicDate', direction: 'desc' }]
  })

  return (
    <>
      <SliceZone slices={page.data.slices} components={components} />
      <Bounded as='section'>
        <div className='grid grid-cols-1 gap-10 md:grid-cols-2 lg:grid-cols-3'>
          {posts.map((post) => (
            <ArticlePostCard key={post.id} post={post} />
          ))}
        </div>
      </Bounded>
    </>
  )
}

Thanks everyone.

Hi @drl.oucommunity,

Welcome to the community :slight_smile:

You're right, these two routes would be in conflict. What are you trying to display in /:uid ? It would need to be a different type to bai-viet.

Also, in case this wasn't a copy/paste error but a typo in your source code, you have a period instead of a colon after type in:

{ type. 'page', path: '/bai-viet', uid: 'bai-viet' },

Let me know if that helps :slight_smile:

Sorry, Ezekiel! That was my typo. There’s still a conflict, though, as I want to display 'bai-viet' instead of '/:uid'

Here's the solution I found:

  1. On the admin page, I removed the page with UID == 'bai-viet' then created a new page with a UID like articles (while keeping the 'bai-viet' folder in 'app/bai-viet').
  2. In app/bai-viet/page.tsx I query:

const page = await client.getByUID('page', 'articles').catch(() => notFound());

instead of:

const page = await client.getByUID('page', 'bai-viet').catch(() => notFound());

Override routes

const routes: prismic.ClientConfig['routes'] = [
    { type: 'page', path: '/bai-viet', uid: 'articles' }
];

This works, but my site now has two URLs related to blog posts (<domain>/articles and <domain>/bai-viet). I think that’s fine since I’m hosting on Vercel and can use vercel.json to set up redirects.

Do you have any idea resolve this problem? Thanks

I think I can help, I just need more clarification on what it is you're trying to display and do with your routes so we can get that right :slight_smile:

You can query data in different places without it necessarily impacting the routes. Is /bai-viet meant to be a page that displays articles, and so you ultimately want a path like /bai-viet/:uid? Or are you trying to get separately <domain>/bai-viet, and some other completely unrelated pages like <domain>/:uid?

Yes, this is what I want.

Example in my case:

In admin dashboard, create new page with UID === 'bai-viet'

At local, I create 'bai-viet' folder in app (page.tsx and [uid]/page.tsx) (this folder I custom show all post, post details).

ex: app/bai-viet/page.tsx

export default async function ArticlePage() {
  const client = createClient()
  const page = await client.getByUID('page', 'bai-viet').catch(() => notFound())

  const posts = await client.getAllByType('article_post', {
    orderings: [{ field: 'my.article_post.publicDate', direction: 'desc' }]
  })

  return (
    <>
      <SliceZone slices={page.data.slices} components={components} />
      <Bounded as='section'>
        <div className='grid grid-cols-1 gap-10 md:grid-cols-2 lg:grid-cols-3'>
          {posts.map((post) => (
            <ArticlePostCard key={post.id} post={post} />
          ))}
        </div>
      </Bounded>
    </>
  )
}

But, maybe in app/[uid]/page.tsx override them, alway show data than in app/bai-viet/page.tsx.

How to keep UID === 'bai-viet' in admin dashboard and when navigate <domain>/bai-viet on website (show data of app/bai-viet/page.tsx instead of app/[uid]/page.tsx) ?

Thanks for the clarification!

So what you need to do is differentiate the type between the documents that will be in /:uid and the one in /bai-viet. Whichever way you go about it is up to you and what makes the most sense for your project, but ideally you would want your routes to be like this (for example):

const routes: prismic.ClientConfig['routes'] = [
{ type: 'page', path: '/', uid: 'home' },
{ type: 'page', path: '/:uid' },
{ type. 'bai_viet', path: '/bai-viet', uid: 'bai-viet' },
{ type: 'article_post', path: '/bai-viet/:uid' },
]

This will work and let you have /:uid and /bai-viet with no conflicting path and this folder configuration:

├ app
├─ layout.tsx
├─ page.tsx
├─ [uid]
│   └─ page.tsx
├─ bai-viet
       └─ [uid]
│          ├─ page.tsx
│   ├    page.tsx
│  ........

This will require you to create a new page type (whichever one you choose) in the slice machine and "transfer" what you've already done in bai-viet or :uid, but it will save you the headache in the long run :slight_smile:

Let me know how that goes!