1- /*
2- * Copyright (c) Facebook, Inc. and its affiliates.
3- */
4-
5- import { Fragment , useMemo } from 'react' ;
6- import { useRouter } from 'next/router' ;
1+ // src/app/[[...markdownPath]]/page.js
2+ import { Fragment } from 'react' ;
3+ import fs from 'fs/promises' ;
4+ import path from 'path' ;
75import { Page } from 'components/Layout/Page' ;
8- import sidebarHome from '../sidebarHome.json' ;
9- import sidebarLearn from '../sidebarLearn.json' ;
10- import sidebarReference from '../sidebarReference.json' ;
11- import sidebarCommunity from '../sidebarCommunity.json' ;
12- import sidebarBlog from '../sidebarBlog.json' ;
6+ import sidebarHome from '../../ sidebarHome.json' ;
7+ import sidebarLearn from '../../ sidebarLearn.json' ;
8+ import sidebarReference from '../../ sidebarReference.json' ;
9+ import sidebarCommunity from '../../ sidebarCommunity.json' ;
10+ import sidebarBlog from '../../ sidebarBlog.json' ;
1311import { MDXComponents } from 'components/MDX/MDXComponents' ;
1412import compileMDX from 'utils/compileMDX' ;
15- import { generateRssFeed } from '../utils/rss' ;
16-
17- export default function Layout ( { content, toc, meta, languages} ) {
18- const parsedContent = useMemo (
19- ( ) => JSON . parse ( content , reviveNodeOnClient ) ,
20- [ content ]
21- ) ;
22- const parsedToc = useMemo ( ( ) => JSON . parse ( toc , reviveNodeOnClient ) , [ toc ] ) ;
23- const section = useActiveSection ( ) ;
24- let routeTree ;
25- switch ( section ) {
26- case 'home' :
27- case 'unknown' :
28- routeTree = sidebarHome ;
29- break ;
30- case 'learn' :
31- routeTree = sidebarLearn ;
32- break ;
33- case 'reference' :
34- routeTree = sidebarReference ;
35- break ;
36- case 'community' :
37- routeTree = sidebarCommunity ;
38- break ;
39- case 'blog' :
40- routeTree = sidebarBlog ;
41- break ;
42- }
43- return (
44- < Page
45- toc = { parsedToc }
46- routeTree = { routeTree }
47- meta = { meta }
48- section = { section }
49- languages = { languages } >
50- { parsedContent }
51- </ Page >
52- ) ;
53- }
54-
55- function useActiveSection ( ) {
56- const { asPath} = useRouter ( ) ;
57- const cleanedPath = asPath . split ( / [ \? \# ] / ) [ 0 ] ;
58- if ( cleanedPath === '/' ) {
59- return 'home' ;
60- } else if ( cleanedPath . startsWith ( '/reference' ) ) {
61- return 'reference' ;
62- } else if ( asPath . startsWith ( '/learn' ) ) {
63- return 'learn' ;
64- } else if ( asPath . startsWith ( '/community' ) ) {
65- return 'community' ;
66- } else if ( asPath . startsWith ( '/blog' ) ) {
67- return 'blog' ;
68- } else {
69- return 'unknown' ;
70- }
71- }
13+ import { generateRssFeed } from '../../utils/rss' ;
7214
7315// Deserialize a client React tree from JSON.
7416function reviveNodeOnClient ( parentPropertyName , val ) {
7517 if ( Array . isArray ( val ) && val [ 0 ] == '$r' ) {
76- // Assume it's a React element.
7718 let Type = val [ 1 ] ;
7819 let key = val [ 2 ] ;
7920 if ( key == null ) {
80- key = parentPropertyName ; // Index within a parent.
21+ key = parentPropertyName ;
8122 }
8223 let props = val [ 3 ] ;
8324 if ( Type === 'wrapper' ) {
@@ -97,62 +38,77 @@ function reviveNodeOnClient(parentPropertyName, val) {
9738 }
9839}
9940
100- // Put MDX output into JSON for client.
101- export async function getStaticProps ( context ) {
102- generateRssFeed ( ) ;
103- const fs = require ( 'fs' ) ;
104- const rootDir = process . cwd ( ) + '/src/content/' ;
41+ function getActiveSection ( pathname ) {
42+ if ( pathname === '/' ) {
43+ return 'home' ;
44+ } else if ( pathname . startsWith ( '/reference' ) ) {
45+ return 'reference' ;
46+ } else if ( pathname . startsWith ( '/learn' ) ) {
47+ return 'learn' ;
48+ } else if ( pathname . startsWith ( '/community' ) ) {
49+ return 'community' ;
50+ } else if ( pathname . startsWith ( '/blog' ) ) {
51+ return 'blog' ;
52+ } else {
53+ return 'unknown' ;
54+ }
55+ }
56+
57+ async function getRouteTree ( section ) {
58+ switch ( section ) {
59+ case 'home' :
60+ case 'unknown' :
61+ return sidebarHome ;
62+ case 'learn' :
63+ return sidebarLearn ;
64+ case 'reference' :
65+ return sidebarReference ;
66+ case 'community' :
67+ return sidebarCommunity ;
68+ case 'blog' :
69+ return sidebarBlog ;
70+ }
71+ }
10572
106- // Read MDX from the file.
107- let path = ( context . params . markdownPath || [ ] ) . join ( '/' ) || 'index' ;
73+ // This replaces getStaticProps
74+ async function getPageContent ( markdownPath ) {
75+ const rootDir = path . join ( process . cwd ( ) , 'src/content' ) ;
76+ let mdxPath = markdownPath ?. join ( '/' ) || 'index' ;
10877 let mdx ;
78+
10979 try {
110- mdx = fs . readFileSync ( rootDir + path + '.md' , 'utf8' ) ;
80+ mdx = await fs . readFile ( path . join ( rootDir , mdxPath + '.md' ) , 'utf8' ) ;
11181 } catch {
112- mdx = fs . readFileSync ( rootDir + path + '/ index.md', 'utf8' ) ;
82+ mdx = await fs . readFile ( path . join ( rootDir , mdxPath , ' index.md') , 'utf8' ) ;
11383 }
11484
115- const { toc, content, meta, languages} = await compileMDX ( mdx , path , { } ) ;
116- return {
117- props : {
118- toc,
119- content,
120- meta,
121- languages,
122- } ,
123- } ;
85+ // Generate RSS feed during build time
86+ if ( process . env . NODE_ENV === 'production' ) {
87+ await generateRssFeed ( ) ;
88+ }
89+
90+ return await compileMDX ( mdx , mdxPath , { } ) ;
12491}
12592
126- // Collect all MDX files for static generation.
127- export async function getStaticPaths ( ) {
128- const { promisify} = require ( 'util' ) ;
129- const { resolve} = require ( 'path' ) ;
130- const fs = require ( 'fs' ) ;
131- const readdir = promisify ( fs . readdir ) ;
132- const stat = promisify ( fs . stat ) ;
133- const rootDir = process . cwd ( ) + '/src/content' ;
93+ // This replaces getStaticPaths
94+ export async function generateStaticParams ( ) {
95+ const rootDir = path . join ( process . cwd ( ) , 'src/content' ) ;
13496
135- // Find all MD files recursively.
13697 async function getFiles ( dir ) {
137- const subdirs = await readdir ( dir ) ;
98+ const entries = await fs . readdir ( dir , { withFileTypes : true } ) ;
13899 const files = await Promise . all (
139- subdirs . map ( async ( subdir ) => {
140- const res = resolve ( dir , subdir ) ;
141- return ( await stat ( res ) ) . isDirectory ( )
100+ entries . map ( async ( entry ) => {
101+ const res = path . resolve ( dir , entry . name ) ;
102+ return entry . isDirectory ( )
142103 ? getFiles ( res )
143104 : res . slice ( rootDir . length + 1 ) ;
144105 } )
145106 ) ;
146- return (
147- files
148- . flat ( )
149- // ignores `errors/*.md`, they will be handled by `pages/errors/[errorCode].tsx`
150- . filter ( ( file ) => file . endsWith ( '.md' ) && ! file . startsWith ( 'errors/' ) )
151- ) ;
107+ return files
108+ . flat ( )
109+ . filter ( ( file ) => file . endsWith ( '.md' ) && ! file . startsWith ( 'errors/' ) ) ;
152110 }
153111
154- // 'foo/bar/baz.md' -> ['foo', 'bar', 'baz']
155- // 'foo/bar/qux/index.md' -> ['foo', 'bar', 'qux']
156112 function getSegments ( file ) {
157113 let segments = file . slice ( 0 , - 3 ) . replace ( / \\ / g, '/' ) . split ( '/' ) ;
158114 if ( segments [ segments . length - 1 ] === 'index' ) {
@@ -163,17 +119,33 @@ export async function getStaticPaths() {
163119
164120 const files = await getFiles ( rootDir ) ;
165121
166- const paths = files . map ( ( file ) => ( {
167- params : {
168- markdownPath : getSegments ( file ) ,
169- // ^^^ CAREFUL HERE.
170- // If you rename markdownPath, update patches/next-remote-watch.patch too.
171- // Otherwise you'll break Fast Refresh for all MD files.
172- } ,
122+ return files . map ( ( file ) => ( {
123+ markdownPath : getSegments ( file ) ,
173124 } ) ) ;
125+ }
126+
127+ export default async function WrapperPage ( { params} ) {
128+ const { markdownPath} = params ;
129+ const { content, toc, meta, languages} = await getPageContent ( markdownPath ) ;
130+
131+ const pathname = '/' + ( markdownPath ?. join ( '/' ) || '' ) ;
132+ const section = getActiveSection ( pathname ) ;
133+ const routeTree = await getRouteTree ( section ) ;
174134
175- return {
176- paths : paths ,
177- fallback : false ,
178- } ;
135+ const parsedContent = JSON . parse ( content , reviveNodeOnClient ) ;
136+ const parsedToc = JSON . parse ( toc , reviveNodeOnClient ) ;
137+
138+ return (
139+ < Page
140+ toc = { parsedToc }
141+ routeTree = { routeTree }
142+ meta = { meta }
143+ section = { section }
144+ languages = { languages } >
145+ { parsedContent }
146+ </ Page >
147+ ) ;
179148}
149+
150+ // Configure dynamic segments to be statically generated
151+ export const dynamicParams = false ;
0 commit comments