Skip to content

Sincere request for help:Multiple Routes Failed 诚恳的求助 #4357

@LeifWebber

Description

@LeifWebber

中文在结尾(Also have Chinese)

I really like the style of nextra, so I don't want to give it up. If anyone sees my question below, I hope they can provide guidance on how to complete this practice. Thank you very much.

My Environment

  • Nextra version: nextra v4
  • My operating system: Windows 11
  • My editor: Cursor
  • Node version: v20.18.2

My Approach to Organizing Article Structure

I use the content directory, located under src.

My Requirements

  1. I need a project landing page, accessible via localhost:3000. This landing page is located at src\app\page.tsx. It cannot be written using md or mdx files, as that does not meet my requirements.

  2. I want to have multiple independent documentation sets, each displayed in the navigation bar. For example:

    • The "Business Plan" in the navigation bar corresponds to localhost:3000/docs/, which leads to an independent documentation set with various subdirectories. If a folder contains all the mdx files for this documentation, such as glossary.mdx, it should be accessible via localhost:3000/docs/glossary.

    • The "Technical Manual" in the navigation bar corresponds to localhost:3000/tech/, which also leads to an independent documentation set with various subdirectories. If a folder contains all the mdx files for this documentation, such as api.mdx, it should be accessible via localhost:3000/tech/api.

    The conflict arises:

    If I use a structure like app/docs/[[...mdxPath]]/page.jsx and configure contentDirBasePath: 'docs', how can I implement the matching for localhost:3000/tech for my other independent documentation set?

My Attempts

1. Using Multiple Routes

Actions:

I created the following directory structure:

app/
├── docs/[[...mdxPath]]/page.jsx # Handles /docs/* paths
└── tech/[[...mdxPath]]/page.jsx # Handles /tech/* paths
└── ......

And modified the page.jsx files as follows:

// app/docs/[[...mdxPath]]/page.jsx
import { generateStaticParamsFor, importPage } from 'nextra/pages'

// Specifies 'docs' as the content source
export const generateStaticParams = generateStaticParamsFor('docs')

// Rest of the code remains unchanged...
// app/tech/[[...mdxPath]]/page.jsx
import { generateStaticParamsFor, importPage } from 'nextra/pages'

// Specifies 'tech' as the content source
export const generateStaticParams = generateStaticParamsFor('tech')

// Rest of the code remains unchanged...

Correspondingly, the content directory structure is organized as:

   content/
   ├── docs/            # Business Plan content
   │   ├── index.mdx
   │   └── glossary.mdx
   └── tech/            # Technical Manual content
       ├── index.mdx
       └── api.mdx

Modified next.config.mjs:

const withNextra = nextra({
contentDirBasePath: '/' // Keeps the root path configuration
})

Results:

The console throws an error:

Bash

Error: Page "/docs/[[...mdxPath]]/page" is missing param "/docs" in "generateStaticParams()", which is required with "output: export" config.
at DevServer.renderToResponseWithComponentsImpl (file://D:\Projects\sanyeyun_docs\node_modules\next\dist\server\base-server.js:1186:49)

I didn't know what to do, so I removed the following from next.config.mjs:

const nextConfig = {
    // output: 'export', // Removed this line
    images: {
    unoptimized: true
    }
}

Restarting the development server still results in the following error:

- error [nextra] Error while loading { pathSegments: [] } Error: Cannot find module './undefined'
    at webpackContextResolve (D:\Projects\sanyeyun_docs\.next\server\app\docs\[[...mdxPath]]\page.js:139:11)
    at webpackContext (D:\Projects\sanyeyun_docs\.next\server\app\docs\[[...mdxPath]]\page.js:134:11)
    at async Page (src\app\docs\[[...mdxPath]]\page.jsx:16:17)
  14 | export default async function Page(props) {
  15 |   const params = await props.params
> 16 |   const result = await importPage(params.mdxPath)
     |                 ^
  17 |   const { default: MDXContent, toc, metadata } = result
  18 |   return (
  19 |     <Wrapper toc={toc} metadata={metadata}> {
  code: 'MODULE_NOT_FOUND'
}

2. Using a Single-Layer Route but Adjusting the Structure in the content Directory

Actions:

  1. I adjusted the app directory to the following structure:
app/
├── [[...mdxPath]]/page.jsx # [[...mdxPath]] directly under the root
├── page.tsx
├── layout.jsx
├── ......
  1. And adjusted the structure under the content directory:
   content/
   ├── docs/            # Business Plan content
   │   ├── index.mdx
   │   └── glossary.mdx
   └── tech/            # Technical Manual content
       ├── index.mdx
       └── api.mdx
  1. And changed the contentDirBasePath value to '/'.

Now, when I try to start the development server, I encounter the following error, which prevents it from starting:

[Error: You cannot define a route with the same specificity as a optional catch-all route ("/" and "/[[...mdxPath]]").]

So, I removed src\app\page.tsx and created a new src\content\index.mdx to temporarily replace the landing page.

I created a new src\content\_meta.js with the following content:

export default {
    index: {
        display: 'hidden',
    },
    docs: {
        type: 'page',
        title: 'Business Plan',
        display: 'children'
    },
    tech: {
        type: 'page',
        title: 'Technical Manual',
        display: 'children'
    },
}

This seems to be very close to what I want, but there are two unacceptable points:

  1. I no longer have a custom landing page because the landing page is written in mdx.
  2. If I want to independently configure the layout.jsx for the tech files in the future, it seems impossible because the content directory can only parse mdx files.

Chinese Version 中文:

我很喜欢 nextra 的风格,所以我不想放弃它。如果有人能看到我下面提出的问题,希望能简单指导我怎样完成这个实践。不胜感激。

我的环境

nextra version:nextra v4
我的操作系统:windows11
我的编辑器:cursor
node version:v20.18.2

我选择组织文章结构的方式:

使用 content 目录,并且在 src 下。

我的需求

  1. 我需要有一个项目的亮点首页,能通过localhost:3000访问到,首页地址在src\app\page.tsx,首页不能用 md或者mdx文件写,因为这达不到我的要求。

  2. 我不止想拥有一个文档,而是多个独立文档,他们应当分别显示在导航栏。举例:

    • 导航栏的“商业计划书”对应 localhost:3000/docs/,点进去以后是一个有各种子目录层级的独立文档。在某个文件夹内存放所有该文档的 mdx 文件,比如在其中存放了glossary.mdx,就可通过 localhost:3000/docs/glossary访问。

    • 导航栏的“技术手册”对应 localhost:3000/tech/,点进去以后也是一个有各种子目录层级的独立文档。在某个文件夹内存放所有该文档的 mdx 文件,比如存放了api.mdx,就可通过 localhost:3000/tech/api 访问。

冲突点在于:
如果我使用 app/docs/[[...mdxPath]]/page.jsx 这样的结构,并且配置contentDirBasePath: 'docs',那我另一个独立文档又该怎么实现对 localhost:3000/tech 结尾的匹配呢?

我的尝试

1. 采用多重路由

操作:

我创建如下的目录结构:

   app/
   ├── docs/[[...mdxPath]]/page.jsx  # 处理 /docs/* 路径
   └── tech/[[...mdxPath]]/page.jsx  # 处理 /tech/* 路径
   └── ......

并分别更改其中的 page.jsx

   // app/docs/[[...mdxPath]]/page.jsx
   import { generateStaticParamsFor, importPage } from 'nextra/pages'
   
   // 指定使用 'docs' 作为内容源
   export const generateStaticParams = generateStaticParamsFor('docs')
   
   // 其余代码保持不变...
   // app/tech/[[...mdxPath]]/page.jsx
   import { generateStaticParamsFor, importPage } from 'nextra/pages'
   
   // 指定使用 'tech' 作为内容源
   export const generateStaticParams = generateStaticParamsFor('tech')
   
   // 其余代码保持不变...

相应的组织目录结构:

   content/
   ├── docs/            # 商业计划书内容
   │   ├── index.mdx
   │   └── glossary.mdx
   └── tech/            # 技术手册内容
       ├── index.mdx
       └── api.mdx

调整next.config.mjs

const withNextra = nextra({
	contentDirBasePath: '/' // 保持根路径配置
})

结果:

控制台报错:

Error: Page "/docs/[[...mdxPath]]/page" is missing param "/docs" in "generateStaticParams()", which is required with "output: export" config.  
at DevServer.renderToResponseWithComponentsImpl (file://D:\Projects\sanyeyun_docs\node_modules\next\dist\server\base-server.js:1186:49)

我不知道该怎么办,于是我删除了next.config.mjs里的以下内容:

   const nextConfig = {
-    // output: 'export',  删除这行
     images: {
       unoptimized: true
     }
   }

再次启动开发服务器,还是有如下报错:

- error [nextra] Error while loading { pathSegments: [] } Error: Cannot find module './undefined'
    at webpackContextResolve (D:\Projects\sanyeyun_docs\.next\server\app\docs\[[...mdxPath]]\page.js:139:11)
    at webpackContext (D:\Projects\sanyeyun_docs\.next\server\app\docs\[[...mdxPath]]\page.js:134:11)
    at async Page (src\app\docs\[[...mdxPath]]\page.jsx:16:17)
  14 | export default async function Page(props) {
  15 |   const params = await props.params
> 16 |   const result = await importPage(params.mdxPath)
     |                 ^
  17 |   const { default: MDXContent, toc, metadata } = result
  18 |   return (
  19 |     <Wrapper toc={toc} metadata={metadata}> {
  code: 'MODULE_NOT_FOUND'
}

2. 采用单层路由,但是调整 content 目录里的结构

操作

  1. 我把 app 目录调整成如下结构:
   app/
   ├── [[...mdxPath]]/page.jsx  # 让[[...mdxPath]]直接在根目录
   ├── page.tsx
   ├── layout.jsx
   ├── ......
  1. 并且调整了 content 目录下的结构:
   content/
   ├── docs/            # 商业计划书内容
   │   ├── index.mdx
   │   └── glossary.mdx
   └── tech/            # 技术手册内容
       ├── index.mdx
       └── api.mdx
  1. 并且把 contentDirBasePath 值更改为 '/'

然后我现在尝试启动开发服务器,发现有报错如下,导致启动不了:

[Error: You cannot define a route with the same specificity as a optional catch-all route ("/" and "/[[...mdxPath]]").]  

于是我删除了 src\app\page.tsx ,并且新建了一个 src\content\index.mdx来暂时替代首页。
我新建了 src\content\_meta.js,内容如下:

export default {
    index: {
        display: 'hidden',
    },
    docs:   {
        type: 'page',
        title: '商业计划书',
        display: 'children'
    },
    tech: {
        type: 'page',
        title: '技术手册',
        display: 'children'
    },
  }

这次似乎很接近的我想要的样子了,但是有两点的难以接受:

  1. 我不再有自定义的首页,因为首页是用 mdx 写的。
  2. 如果之后我想独立配置 tech 文件的 layout.jsx ,这似乎就不能实现,因为 content 目录下似乎只能解析 mdx 文件。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions