I am making a blog with two level nested routes: example.com/blogs/[chapterID]/[postID] The static posts saved in local folder (outside the app folder) as markdown files.
The urls are stored in the blogs.json.
[
{
"header": "Header for Category1",
"id": "category1",
"topicList": [
{
"title": "post1 title",
"url": "cat1-post1.md"
},
{
"title": "post2 title",
"url": "cat1-post2.md"
},
{
"title": "post3 title",
"url": "cat1-post3.md"
}
]
},
{
"header": "Header for Category 2",
"id": "category2",
"topicList": [
{
"title": "Cat2 Post1 title",
"url": "cat2-post1.md"
},
{
"title": "Cat2 Post2 title ",
"url": "cat2-post2.md"
},
{
"title": "Cat2 Post3 title ",
"url": "cat2-post3.md"
}
]
},
{
"header": "Header for Category 3",
"id": "category3",
"topicList": [
{
"title": "Cat3 Post1 title",
"url": "cat3-post1.md"
},
{
"title": "Cat3 Post2 title ",
"url": "cat3-post1.md"
}
]
}
]
The page works but I am having hardtime to generate static paths and props.
My page.tsx inside [postID] is-
import React from 'react'
import fs from "fs"
import Markdown from "react-markdown"
import rehypeKatex from "rehype-katex"
import remarkMath from "remark-math"
import rehypeRaw from "rehype-raw"
import matter from "gray-matter"
import 'katex/dist/katex.min.css'
import BlogMenu from '../../blogs.json'
import path from "path"
const allPosts = BlogMenu.flatMap(({ header, id, topicList }) =>
topicList.map((topics) => ({
sectionName: header,
sectionId: id,
...topics,
})),
);
const folder = path.join(process.cwd(), 'src/BlogPages');// declare it outside of app folder
const getPostContent = (chapterID:string, postID: string) => {
const file = `${folder}/${chapterID}/${postID}.md`;
const content = fs.readFileSync(file, "utf8");
const matterResult = matter(content);
return matterResult;
};
export async function getStaticPaths() {
return {
paths: allPosts.map((post) => ({
params: {
chapterID: post.sectionId,
postID: post.url
},
})),
fallback: false,
};
}
export async function getStaticProps(chapterID:string, postID: string) {
const postProps = getPostContent(chapterID, postID) // Retrieve data for given type/slug pair
return {
props: {
data: postProps
}
}
}
const BlogPage = (props: any) => {
const chapterID = props.params.chapterID
const postID = props.params.postID;
const post = getPostContent(chapterID, postID)
return (
<>
<h1>{post.data.title}</h1>
<hr className="my-6 border border-dashed bg-teal-600 h-0.5" />
<article className="prose lg:prose-xl">
<Markdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex, rehypeRaw]}>
{post.content}</Markdown>
</article>
</>
)
}
export default BlogPage
When I run npm run build
it shows the error-
> next build
▲ Next.js 14.0.4
✓ Creating an optimized production build
✓ Compiled successfully
Linting and checking validity of types ...Failed to compile.
src/app/(routes)/blogs/[chapterID]/[postID]/page.tsx
Type error: Page "src/app/(routes)/blogs/[chapterID]/[postID]/page.tsx" does not match the required types of a Next.js Page.
"getStaticPaths" is not a valid Page export field.
And for getStaticProps() I am getting the error-
File path:
./src/app/(routes)/blogs/[chapterID]/[postID]/page.tsx
⨯ ./src/app/(routes)/blogs/[chapterID]/[postID]/page.tsx
ReactServerComponentsError:
"getStaticProps" is not supported in app/. Read more: https://nextjs.org/docs/app/building-your-application/data-fetching
Any suggestion about solving the error will be appreciated. Thanks in advance.
After a lots of searching, it seems that since NextJS 13 they have introduced new app
directory and calling getStaticProps()
or getStaticPaths()
inside the app
will cause the error. This error can be solved by using generateStaticParams()
instead.
export async function generateStaticParams() {
return allPosts.map((post) => ({
chapterID: post.sectionId,
postID: post.url
}))
}
I have removed my getStaticProps()
and getStaticPaths()
functions and used the above code to generate static slug. Hope it will help someone. You will find more details about generateStaticParams()
in this link.