Skip to content

Commit

Permalink
Remove requirement page.{jsx,tsx} pages to have exported metadata
Browse files Browse the repository at this point in the history
… object (#4154)

* upd

* upd

* upd

* upd

* upd

* upd

* upd

* upd

* upd

* fix

* prettier

* fix tests

* fix tests

* upd

* [skip ci]

* upd

* upd
  • Loading branch information
dimaMachina authored Feb 5, 2025
1 parent 1b44417 commit ca67a19
Show file tree
Hide file tree
Showing 15 changed files with 241 additions and 36 deletions.
7 changes: 7 additions & 0 deletions .changeset/spotty-carrots-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"nextra": patch
"nextra-theme-blog": patch
"nextra-theme-docs": patch
---

remove requirement `page.{jsx,tsx}` pages to have exported `metadata` object
2 changes: 1 addition & 1 deletion docs/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const metadata: Metadata = {

const banner = (
<Banner dismissible={false}>
🎉 Nextra 4.0 is released. Dima Machina is looking{' '}
🎉 Nextra 4.0 is released. dimaMachina is looking{' '}
<Link href="https://github.com/dimaMachina">
for a new job or consulting
</Link>
Expand Down
2 changes: 0 additions & 2 deletions examples/docs/src/app/blog/page.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export const metadata = {}

export default function BlogPage() {
return (
<h1
Expand Down
3 changes: 2 additions & 1 deletion examples/docs/src/app/layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export default async function RootLayout({ children }) {
chatLink="https://discord.gg/hEM84NMkRv"
/>
)
const pageMap = await getPageMap()
return (
<html lang="en" dir="ltr" suppressHydrationWarning>
<Head faviconGlyph="✦" />
Expand All @@ -48,7 +49,7 @@ export default async function RootLayout({ children }) {
editLink="Edit this page on GitHub"
docsRepositoryBase="https://github.com/shuding/nextra/blob/main/examples/docs"
sidebar={{ defaultMenuCollapseLevel: 1 }}
pageMap={await getPageMap()}
pageMap={pageMap}
>
{children}
</Layout>
Expand Down
2 changes: 0 additions & 2 deletions examples/docs/src/app/page.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export const metadata = {}

export default function IndexPage() {
return (
<h1
Expand Down
6 changes: 0 additions & 6 deletions examples/docs/src/app/showcase/(overview)/page.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
/**
* @see https://github.com/shuding/nextra/issues/4148
*/

export const metadata = {}

export default function Page() {
return (
<h1
Expand Down
6 changes: 3 additions & 3 deletions examples/docs/src/content/themes/docs/bleed.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const metadata = {
sidebarTitle: 'Bleed'
}
---
sidebarTitle: Bleed
---

# Bleed Component

Expand Down
6 changes: 3 additions & 3 deletions examples/docs/src/content/themes/docs/callout.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const metadata = {
sidebarTitle: 'Callout'
}
---
sidebarTitle: Callout
---

# Callout Component

Expand Down
6 changes: 3 additions & 3 deletions examples/docs/src/content/themes/docs/tabs.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const metadata = {
sidebarTitle: 'Tabs'
}
---
sidebarTitle: Tabs
---

# Tabs Component

Expand Down
3 changes: 2 additions & 1 deletion examples/swr-site/content/en/_meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ export default {
type: 'page',
display: 'hidden',
theme: {
typesetting: 'article'
typesetting: 'article',
toc: false
}
},
docs: {
Expand Down
175 changes: 175 additions & 0 deletions packages/nextra/src/server/__tests__/to-js.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import path from 'node:path'
import { CWD } from '../constants.js'
import { findMetaAndPageFilePaths } from '../page-map/find-meta-and-page-file-paths.js'
import { convertPageMapToJs } from '../page-map/to-js.js'
import { convertToPageMap } from '../page-map/to-page-map.js'

describe('convertPageMapToJs()', () => {
it('should work for docs example', async () => {
const cwd = path.join(CWD, '..', '..', 'examples', 'docs')
const filePaths = await findMetaAndPageFilePaths({
dir: path.join(cwd, 'src/app'),
cwd,
contentDir: 'src/content'
})
const { pageMap, mdxPages } = convertToPageMap({ filePaths })

const result = convertPageMapToJs({ pageMap, mdxPages })
expect(result).toMatchInlineSnapshot(`
"import { normalizePageMap, getMetadata } from 'nextra/page-map'
import meta from "private-next-root-dir/src/content/_meta.js";
import features_meta from "private-next-root-dir/src/content/features/_meta.js";
import {metadata as features_i18n} from "private-next-root-dir/src/content/features/i18n.mdx?metadata";
import {metadata as features_image} from "private-next-root-dir/src/content/features/image.mdx?metadata";
import {metadata as features_latex} from "private-next-root-dir/src/content/features/latex.mdx?metadata";
import {metadata as features_mdx} from "private-next-root-dir/src/content/features/mdx.mdx?metadata";
import {metadata as features_ssg} from "private-next-root-dir/src/content/features/ssg.mdx?metadata";
import {metadata as features_themes} from "private-next-root-dir/src/content/features/themes.mdx?metadata";
import themes_meta from "private-next-root-dir/src/content/themes/_meta.js";
import themes_blog_meta from "private-next-root-dir/src/content/themes/blog/_meta.js";
import {metadata as themes_blog_index} from "private-next-root-dir/src/content/themes/blog/index.mdx?metadata";
import themes_docs_meta from "private-next-root-dir/src/content/themes/docs/_meta.js";
import {metadata as themes_docs_bleed} from "private-next-root-dir/src/content/themes/docs/bleed.mdx?metadata";
import {metadata as themes_docs_callout} from "private-next-root-dir/src/content/themes/docs/callout.mdx?metadata";
import {metadata as themes_docs_configuration} from "private-next-root-dir/src/content/themes/docs/configuration.mdx?metadata";
import {metadata as themes_docs_index} from "private-next-root-dir/src/content/themes/docs/index.mdx?metadata";
import {metadata as themes_docs_tabs} from "private-next-root-dir/src/content/themes/docs/tabs.mdx?metadata";
import * as src_app_blog_page from "private-next-root-dir/src/app/blog/page.jsx";
import {metadata as index} from "private-next-root-dir/src/content/index.mdx?metadata";
import * as src_app_showcase_overview_page from "private-next-root-dir/src/app/showcase/(overview)/page.jsx";
import {metadata as advanced_code_highlighting} from "private-next-root-dir/src/content/advanced/code-highlighting.mdx?metadata";
import {metadata as get_started} from "private-next-root-dir/src/content/get-started.mdx?metadata";
import {metadata as mermaid} from "private-next-root-dir/src/content/mermaid.mdx?metadata";
import {metadata as page} from "private-next-root-dir/src/content/page.mdx?metadata";
export const pageMap = normalizePageMap([{
data: meta
}, {
name: "features",
route: "/features",
children: [{
data: features_meta
}, {
name: "i18n",
route: "/features/i18n",
frontMatter: features_i18n
}, {
name: "image",
route: "/features/image",
frontMatter: features_image
}, {
name: "latex",
route: "/features/latex",
frontMatter: features_latex
}, {
name: "mdx",
route: "/features/mdx",
frontMatter: features_mdx
}, {
name: "ssg",
route: "/features/ssg",
frontMatter: features_ssg
}, {
name: "themes",
route: "/features/themes",
frontMatter: features_themes
}]
}, {
name: "themes",
route: "/themes",
children: [{
data: themes_meta
}, {
name: "blog",
route: "/themes/blog",
children: [{
data: themes_blog_meta
}, {
name: "index",
route: "/themes/blog",
frontMatter: themes_blog_index
}]
}, {
name: "docs",
route: "/themes/docs",
children: [{
data: themes_docs_meta
}, {
name: "bleed",
route: "/themes/docs/bleed",
frontMatter: themes_docs_bleed
}, {
name: "callout",
route: "/themes/docs/callout",
frontMatter: themes_docs_callout
}, {
name: "configuration",
route: "/themes/docs/configuration",
frontMatter: themes_docs_configuration
}, {
name: "index",
route: "/themes/docs",
frontMatter: themes_docs_index
}, {
name: "tabs",
route: "/themes/docs/tabs",
frontMatter: themes_docs_tabs
}]
}]
}, {
name: "blog",
route: "/blog",
frontMatter: getMetadata(src_app_blog_page)
}, {
name: "index",
route: "/",
frontMatter: index
}, {
name: "showcase",
route: "/showcase",
frontMatter: getMetadata(src_app_showcase_overview_page)
}, {
name: "advanced",
route: "/advanced",
children: [{
name: "code-highlighting",
route: "/advanced/code-highlighting",
frontMatter: advanced_code_highlighting
}]
}, {
name: "get-started",
route: "/get-started",
frontMatter: get_started
}, {
name: "mermaid",
route: "/mermaid",
frontMatter: mermaid
}, {
name: "page",
route: "/page",
frontMatter: page
}])
export const RouteToFilepath = {
"": "index.mdx",
"advanced/code-highlighting": "advanced/code-highlighting.mdx",
"features/i18n": "features/i18n.mdx",
"features/image": "features/image.mdx",
"features/latex": "features/latex.mdx",
"features/mdx": "features/mdx.mdx",
"features/ssg": "features/ssg.mdx",
"features/themes": "features/themes.mdx",
"get-started": "get-started.mdx",
"mermaid": "mermaid.mdx",
"page": "page.mdx",
"themes/blog": "themes/blog/index.mdx",
"themes/docs/bleed": "themes/docs/bleed.mdx",
"themes/docs/callout": "themes/docs/callout.mdx",
"themes/docs/configuration": "themes/docs/configuration.mdx",
"themes/docs": "themes/docs/index.mdx",
"themes/docs/tabs": "themes/docs/tabs.mdx"
}"
`)
})
})
6 changes: 3 additions & 3 deletions packages/nextra/src/server/__tests__/to-page-map.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ describe('generatePageMap()', () => {

expect(convertPageMapToJs({ pageMap, mdxPages, globalMetaPath }))
.toMatchInlineSnapshot(`
"import { normalizePageMap, mergeMetaWithPageMap } from 'nextra/page-map'
"import { normalizePageMap, mergeMetaWithPageMap, getMetadata } from 'nextra/page-map'
import globalMeta from 'private-next-root-dir/app/_meta.global.tsx'
import {metadata as app_about_page} from "private-next-root-dir/app/about/page.mdx?metadata";
import {metadata as app_blog_page} from "private-next-root-dir/app/blog/page.mdx?metadata";
Expand Down Expand Up @@ -574,7 +574,7 @@ describe('generatePageMap()', () => {
import {metadata as app_docs_guide_syntax_highlighting_page} from "private-next-root-dir/app/docs/guide/syntax-highlighting/page.mdx?metadata";
import {metadata as app_docs_guide_turbopack_page} from "private-next-root-dir/app/docs/guide/turbopack/page.mdx?metadata";
import {metadata as app_docs_page} from "private-next-root-dir/app/docs/page.mdx?metadata";
import {metadata as app_page} from "private-next-root-dir/app/page.tsx";
import * as app_page from "private-next-root-dir/app/page.tsx";
import {metadata as app_showcase_page} from "private-next-root-dir/app/showcase/page.mdx?metadata";
import {metadata as app_sponsors_page} from "private-next-root-dir/app/sponsors/page.mdx?metadata";
Expand Down Expand Up @@ -845,7 +845,7 @@ describe('generatePageMap()', () => {
}, {
name: "index",
route: "/",
frontMatter: app_page
frontMatter: getMetadata(app_page)
}, {
name: "showcase",
route: "/showcase",
Expand Down
10 changes: 10 additions & 0 deletions packages/nextra/src/server/page-map/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import type { Metadata } from 'next'

export { normalizePageMap } from './normalize.js'
export { convertToPageMap } from './to-page-map.js'
export { mergeMetaWithPageMap } from './merge-meta-with-page-map.js'
export { getPageMap } from './get.js'
export { createIndexPage } from './index-page.js'

export function getMetadata(
page:
| { metadata: Metadata }
| { generateMetadata: (props: object) => Promise<Metadata> }
): Promise<Metadata> | Metadata {
return 'generateMetadata' in page ? page.generateMetadata({}) : page.metadata
}
10 changes: 9 additions & 1 deletion packages/nextra/src/server/page-map/to-ast.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'node:path'
import type { ArrayExpression } from 'estree'
import type { Import, TItem } from '../../types.js'
import { MARKDOWN_EXTENSION_RE } from '../constants.js'
import { createAstObject } from '../utils.js'

function cleanFilePath(filePath: string): string {
Expand Down Expand Up @@ -38,7 +39,14 @@ export function convertPageMapToAst(
return createAstObject({
name: item.name,
route: item.route,
frontMatter: { type: 'Identifier', name: importName }
frontMatter: MARKDOWN_EXTENSION_RE.test(filePath)
? { type: 'Identifier', name: importName }
: {
type: 'CallExpression',
callee: { type: 'Identifier', name: 'getMetadata' },
arguments: [{ type: 'Identifier', name: importName }],
optional: false
}
})
}
const filePath = item.__metaPath
Expand Down
33 changes: 23 additions & 10 deletions packages/nextra/src/server/page-map/to-js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,20 @@ export function convertPageMapToJs({
value: `private-next-root-dir/${filePath}${isMdx ? METADATA_ONLY_RQ : ''}`
},
specifiers: [
{
local: { type: 'Identifier', name: importName },
...(isMeta
? { type: 'ImportDefaultSpecifier' }
: {
type: 'ImportSpecifier',
imported: { type: 'Identifier', name: 'metadata' }
})
}
isMeta || isMdx
? {
local: { type: 'Identifier', name: importName },
...(isMeta
? { type: 'ImportDefaultSpecifier' }
: {
type: 'ImportSpecifier',
imported: { type: 'Identifier', name: 'metadata' }
})
}
: {
type: 'ImportNamespaceSpecifier',
local: { type: 'Identifier', name: importName }
}
]
}
}
Expand All @@ -60,7 +65,15 @@ export function convertPageMapToJs({
pageMapRawJs = `mergeMetaWithPageMap(${pageMapRawJs}, globalMeta)`
}

const rawJs = `import { ${['normalizePageMap', globalMetaPath && 'mergeMetaWithPageMap'].filter(Boolean).join(', ')} } from 'nextra/page-map'
const rawJs = `import { ${[
'normalizePageMap',
globalMetaPath && 'mergeMetaWithPageMap',
imports.some(
o => !MARKDOWN_EXTENSION_RE.test(o.filePath) && !META_RE.test(o.filePath)
) && 'getMetadata'
]
.filter(Boolean)
.join(', ')} } from 'nextra/page-map'
${globalMetaPath ? `import globalMeta from 'private-next-root-dir/${globalMetaPath}'` : ''}
${importsResult.value}
export const pageMap = normalizePageMap(${pageMapRawJs})
Expand Down

0 comments on commit ca67a19

Please sign in to comment.