vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.77k stars 26.63k forks source link

Global not-found not available in multiple root layouts #55191

Open devjiwonchoi opened 1 year ago

devjiwonchoi commented 1 year ago

Link to the code that reproduces this issue or a replay of the bug

https://github.com/devjiwonchoi/multi-root-layout-not-found

To Reproduce

CodeSandBox Repro Link

  1. Go to the repro link
  2. Go to /404

Current vs. Expected behavior

Current

The multi-root layout group routes cannot have a global not-found since they don't have app/layout.

src/app/not-found.tsx not-found.tsx doesn't have a root layout. To fix this error, make sure every page has a root layout.

I'm trying to clarify how to handle the unmatched URLs if global not-found is not allowed in group routes with multi-root layouts.

Expected

IMO the expected behavior for /404 is displaying the not-found inside the group which has app/(group)/page.tsx.

Verify canary release

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
Binaries:
  Node: 16.17.0
  npm: 8.15.0
  Yarn: 1.22.19
  pnpm: 7.1.0
Relevant Packages:
  next: 13.4.20-canary.23
  eslint-config-next: 13.4.20-canary.23
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.2.2
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

App Router

Additional context

This issue extends #54980

shriekdj commented 12 months ago

This is the Solution We Just Need to Restructure Our Code. Before Restructuring My NextJS Code Look Like this.

src/
    app/
        [...not_found]/page.tsx
        about/page.tsx
        contact/page.tsx
        layout.tsx
        not-found.tsx
   components/
   utils/

After Restructuring The Folders and Files Look Like this.

src/
    app/
       (default_site)/
            about/page.tsx
            contact/page.tsx
            layout.tsx
       (error_layout)/
            [...not_found]/page.tsx
            layout.tsx
            not-found.tsx
   components/
   utils/

Here are 2 layout.tsx Both Containing Root Layout For Example layout.tsx in (default_site)/ contains the global AdSense Code with Google Analytics.

But Error Page Like 404 Page only Contains the google analytics and there is no adsense code there at all.

As Per NextJS Docs We Can Have Multiple RootLayout for Multiple Parts of our site like sub applications by this way.

Here The [...not_found]/page.tsx Only Created Once in error layout.

It's Content Are Like Given Below.

import {notFound} from "next/navigation"

export default function NotFoundCatchAll() {
  notFound()
}

Hope this Solves Your Issue @devjiwonchoi

devjiwonchoi commented 12 months ago

@shriekdj Thanks for the suggestion! Even though your codes can be a workaround, I still think that the global not-found should be supported in this case.

I believe that it is not the developers' responsibility to configure inefficient structure (such as creating another route group for catch-all in your example) which could be resolved if support this issue or better as a default feature.

jmcpeak commented 10 months ago

I just ran into this.

I love routing by convention, but when those conventions don't work - it sucks.

Please fix this nextjs team!

mecaota commented 9 months ago

I also ran into the same problem. I'm glad that I found a solution, but the documentation says that it works when there is no global matching file path. It's unintuitive that it doesn't work with app/not-found.tsx or app/(group route)/not-found.tsx even if you put it there.

https://nextjs.org/docs/app/api-reference/file-conventions/not-found

I would like you to either fix it or write a solution for this in the documentation.

stychu commented 9 months ago

I have the same issue with my folder structure. Unfortunately you soulution @shriekdj doesn't satisfies my requirements as I want the 404 be displayed within my group root which has all authentication and navigation setup already. For second layout which is public and doesn't contain any auth etc. it should handle 404 with its own layout which doesn't seem currently possible..

https://github.com/vercel/next.js/issues/59180

shriekdj commented 9 months ago

@stychu my structure have two grouping layout both have layout.tsx file with same name but different content.

where the (error_layout) have layout.tsx file with it's own layout structure completely different from layout.tsx from (default_site) . then what issue are you facing.

stychu commented 9 months ago

Hi @shriekdj , I misunderstood your answer at first. After looking closely again and adding the [...not_found]/page.tsx inside my GROUP the not-found is being handled within that group <3 exactly what I needed. So my structure is now

.
└── src/
    └── app/
        ├── (auth)/
        │   ├── login/
        │   │   └── page.tsx
        │   └── layout.tsx
        ├── (main) /
        │   ├── [...not-found]/
        │   │   └── page.tsx
        │   ├── pathOne/
        │   │   └── page.tsx
        │   ├── pathTwo/
        │   │   └── page.tsx
        │   ├── error.tsx
        │   ├── layout.tsx
        │   └── not-found.tsx
        └── api/
            └── trpc
ugb-access commented 8 months ago

I am still Facing this. The Only workaround is catch-all routes but I wouldn't say I like this structure as it kills the purpose of group routing.

shriekdj commented 7 months ago

happy to help @stychu

shriekdj commented 7 months ago

@ugb-access what structure you have currently?

benokif commented 7 months ago

Note that the workaround given by shriekdj does not work for static exports.

Navigating to a route that does not exist (here /fakeroute) will give this error:

Server Error
Error: Page "/(main)/[...not-found]/page" is missing param "/fakeroute" in "generateStaticParams()",
which is required with "output: export" config.

This error happened while generating the page. Any console logs will be displayed in the terminal window.

It would be great to get input from the NextJS team on this, this is an import feature that is currently missing from multiple root layout and is not documented

devjiwonchoi commented 6 months ago

Hi everyone, it seems like we could resolve it via setting the global not-found for each groups:

.
└── app/
    ├── (main)/
    │   ├── layout.tsx
    │   ├── not-found.tsx
    │   └── page.tsx
    └── (sub)/
        ├── sub/
        │   └── page.tsx
        ├── layout.tsx
        └── not-found.tsx

EDIT: My bad, I forgot the context. I'll try to bring up this issue.

ugb-access commented 6 months ago

@ugb-access what structure you have currently?

├── (cart) │   └── cart │   ├── layout.js │   └── page.js ├── (checkout) ├── layout.js ├── (main) │   ├── globals.css │   ├── layout.js │   ├── [...not-found] │   │   └── page.js │   ├── not-found.js │   └── page.js

This is my current structure.

shriekdj commented 4 months ago

why reopened the issue @shuding

YYGod0120 commented 3 months ago

Unfortunately, I also encountered this problem. This was my previous file structure, but not-found.tsx is not working.

└─[language]
    │  apple-icon.png
    │  globals.css
    │  layout.tsx
    │  not-found.tsx
    ├─about
    │      layout.tsx
    │      page.tsx
    │
    ├─categories
    │      layout.tsx
    │      page.tsx
    ├─essay
    │  │  essay.css
    │  │  layout.tsx
    │  │
    │  ├─2023-05-03
    │  │  └─405
    │  │          page.tsx
    │
    ├─front
    │  │  layout.tsx
    │  │
    │  └─[categories]
    │      └─[number]
    │              page.tsx

However, I found a similar solution in #50034. using a dynamic catch-all route to catch other not-found page.

└─[language]
    │  apple-icon.png
    │  globals.css
    │  layout.tsx
    │
    ├─about
    │      layout.tsx
    │      page.tsx
    │
    ├─categories
    │      layout.tsx
    │      page.tsx
    ├─essay
    │  │  essay.css
    │  │  layout.tsx
    │  │
    │  ├─2023-05-03
    │  │  └─405
    │  │          page.tsx
    │
    ├─front
    │  │  layout.tsx
    │  │
    │  └─[categories]
    │      └─[number]
    │              page.tsx
    └─[...not-found]
            page.tsx

But I don't think this is a good method; at least it can only catch not-found after the [language] dynamic route segment. Fortunately, I configured middleware to implement i18n, making it look like a global not-found.tsx.