99
1010import { notFound , redirect } from 'next/navigation' ;
1111import { setRequestLocale } from 'next-intl/server' ;
12- import type { FC } from 'react' ;
12+ import type { FC , ReactNode } from 'react' ;
1313
1414import { setClientContext } from '#site/client-context' ;
1515import WithLayout from '#site/components/withLayout' ;
16- import {
17- ENABLE_STATIC_EXPORT_LOCALE ,
18- ENABLE_STATIC_EXPORT ,
19- } from '#site/next.constants.mjs' ;
20- import {
21- PAGE_VIEWPORT ,
22- DYNAMIC_ROUTES ,
23- } from '#site/next.dynamic.constants.mjs' ;
16+ import { ENABLE_STATIC_EXPORT } from '#site/next.constants.mjs' ;
17+ import { ENABLE_STATIC_EXPORT_LOCALE } from '#site/next.constants.mjs' ;
18+ import { PAGE_VIEWPORT } from '#site/next.dynamic.constants.mjs' ;
2419import { dynamicRouter } from '#site/next.dynamic.mjs' ;
2520import { allLocaleCodes , availableLocaleCodes } from '#site/next.locales.mjs' ;
2621import { defaultLocale } from '#site/next.locales.mjs' ;
2722import { MatterProvider } from '#site/providers/matterProvider' ;
23+ import type { Layouts } from '#site/types/layouts' ;
24+ import type { ClientSharedServerContext } from '#site/types/server' ;
2825
2926type DynamicStaticPaths = { path : Array < string > ; locale : string } ;
3027type DynamicParams = { params : Promise < DynamicStaticPaths > } ;
3128
29+ type DynamicPageRender = {
30+ content : ReactNode ;
31+ layout : Layouts ;
32+ context : Partial < ClientSharedServerContext > ;
33+ } ;
34+
3235// This is the default Viewport Metadata
3336// @see https://nextjs.org/docs/app/api-reference/functions/generate-viewport#generateviewport-function
3437export const generateViewport = ( ) => ( { ...PAGE_VIEWPORT } ) ;
@@ -67,11 +70,8 @@ export const generateStaticParams = async () => {
6770 return routes . flat ( ) . sort ( ) ;
6871} ;
6972
70- // This method parses the current pathname and does any sort of modifications needed on the route
71- // then it proceeds to retrieve the Markdown file and parse the MDX Content into a React Component
72- // finally it returns (if the locale and route are valid) the React Component with the relevant context
73- // and attached context providers for rendering the current page
74- const getPage : FC < DynamicParams > = async props => {
73+ // This method is used for retrieving the current locale and pathname from the request
74+ export const getLocaleAndPath = async ( props : DynamicParams ) => {
7575 const { path = [ ] , locale = defaultLocale . code } = await props . params ;
7676
7777 if ( ! availableLocaleCodes . includes ( locale ) ) {
@@ -93,31 +93,11 @@ const getPage: FC<DynamicParams> = async props => {
9393 setRequestLocale ( locale ) ;
9494
9595 // Gets the current full pathname for a given path
96- const pathname = dynamicRouter . getPathname ( path ) ;
97-
98- const staticGeneratedLayout = DYNAMIC_ROUTES . get ( pathname ) ;
99-
100- // If the current pathname is a statically generated route
101- // it means it does not have a Markdown file nor exists under the filesystem
102- // but it is a valid route with an assigned layout that should be rendered
103- if ( staticGeneratedLayout !== undefined ) {
104- // Metadata and shared Context to be available through the lifecycle of the page
105- const sharedContext = { pathname : `/${ pathname } ` } ;
106-
107- // Defines a shared Server Context for the Client-Side
108- // That is shared for all pages under the dynamic router
109- setClientContext ( sharedContext ) ;
110-
111- // The Matter Provider allows Client-Side injection of the data
112- // to a shared React Client Provider even though the page is rendered
113- // within a server-side context
114- return (
115- < MatterProvider { ...sharedContext } >
116- < WithLayout layout = { staticGeneratedLayout } />
117- </ MatterProvider >
118- ) ;
119- }
96+ return [ locale , dynamicRouter . getPathname ( path ) ] as const ;
97+ } ;
12098
99+ // This method is used for retrieving the Markdown content and context
100+ export const getMarkdownContext = async ( locale : string , pathname : string ) => {
121101 // We retrieve the source of the Markdown file by doing an educated guess
122102 // of what possible files could be the source of the page, since the extension
123103 // context is lost from `getStaticProps` as a limitation of Next.js itself
@@ -126,33 +106,57 @@ const getPage: FC<DynamicParams> = async props => {
126106 pathname
127107 ) ;
128108
129- if ( source . length && filename . length ) {
130- // This parses the source Markdown content and returns a React Component and
131- // relevant context from the Markdown File
132- const { content, frontmatter, headings, readingTime } =
133- await dynamicRouter . getMDXContent ( source , filename ) ;
134-
135- // Metadata and shared Context to be available through the lifecycle of the page
136- const sharedContext = {
137- frontmatter : frontmatter ,
138- headings : headings ,
139- pathname : `/${ pathname } ` ,
140- readingTime : readingTime ,
141- filename : filename ,
142- } ;
143-
144- // Defines a shared Server Context for the Client-Side
145- // That is shared for all pages under the dynamic router
146- setClientContext ( sharedContext ) ;
147-
148- // The Matter Provider allows Client-Side injection of the data
149- // to a shared React Client Provider even though the page is rendered
150- // within a server-side context
151- return (
152- < MatterProvider { ...sharedContext } >
153- < WithLayout layout = { frontmatter . layout } > { content } </ WithLayout >
154- </ MatterProvider >
155- ) ;
109+ // This parses the source Markdown content and returns a React Component and
110+ // relevant context from the Markdown File
111+ const { content, frontmatter, headings, readingTime } =
112+ await dynamicRouter . getMDXContent ( source , filename ) ;
113+
114+ // Metadata and shared Context to be available through the lifecycle of the page
115+ const context = {
116+ frontmatter : frontmatter ,
117+ headings : headings ,
118+ pathname : `/${ pathname } ` ,
119+ readingTime : readingTime ,
120+ filename : filename ,
121+ } ;
122+
123+ return [ content , context ] as const ;
124+ } ;
125+
126+ // This method is used for rendering the actual page
127+ export const renderPage : FC < DynamicPageRender > = props => {
128+ // Defines a shared Server Context for the Client-Side
129+ // That is shared for all pages under the dynamic router
130+ setClientContext ( props . context ) ;
131+
132+ // The Matter Provider allows Client-Side injection of the data
133+ // to a shared React Client Provider even though the page is rendered
134+ // within a server-side context
135+ return (
136+ < MatterProvider { ...props . context } >
137+ < WithLayout layout = { props . layout } > { props . content } </ WithLayout >
138+ </ MatterProvider >
139+ ) ;
140+ } ;
141+
142+ // This method parses the current pathname and does any sort of modifications needed on the route
143+ // then it proceeds to retrieve the Markdown file and parse the MDX Content into a React Component
144+ // finally it returns (if the locale and route are valid) the React Component with the relevant context
145+ // and attached context providers for rendering the current page
146+ const getPage : FC < DynamicParams > = async props => {
147+ // Gets the current full pathname for a given path
148+ const [ locale , pathname ] = await getLocaleAndPath ( props ) ;
149+
150+ // Gets the Markdown content and context
151+ const [ content , context ] = await getMarkdownContext ( locale , pathname ) ;
152+
153+ // If we have a filename and layout then we have a page
154+ if ( context . filename && context . frontmatter . layout ) {
155+ return renderPage ( {
156+ content : content ,
157+ layout : context . frontmatter . layout ,
158+ context : context ,
159+ } ) ;
156160 }
157161
158162 return notFound ( ) ;
0 commit comments