I am building a NextJS application and everything is working fine locally. It pulls in all of the data and throws no error.
However, when I try to run npm run build, I get a Prerender Error. I have tried to follow the instructions in the documentation, but I didn't find it very helpful.
Could the problem be that I'm importing the posts using path.join(process.cwd(), './posts') and in this case, when it builds, the paths are somehow different than in development? I can't think of anything else that could be missing.
package.json
{
...
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
....
}
Full error:
Error occurred prerendering page "/blog/Blog". Read more: https://nextjs.org/docs/messages/prerender-error
TypeError: Cannot read property 'slug' of undefined
at Post (/.next/server/chunks/2648.js:223:21)
at d (/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:33:498)
at bb (/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:36:16)
at a.b.render (/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:42:43)
at a.b.read (/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:41:83)
at Object.exports.renderToString (/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:52:138)
at renderPage (/node_modules/next/dist/server/render.js:736:46)
at Object.ctx.renderPage (/.next/server/pages/_document.js:77:26)
at Object.defaultGetInitialProps (/node_modules/next/dist/server/render.js:368:51)
at Function.getInitialProps (/.next/server/chunks/6859.js:651:16)
postdirectory /posts
Here is my file structure:
lib
┗ posts.js
pages
┣ blog
┃ ┣ Blog
┃ ┃ ┗ index.tsx
┃ ┣ Hero
┃ ┃ ┗ index.tsx
┃ ┗ [slug].tsx
┣ knowledge
┃ ┣ components
┃ ┃ ┣ BlogSection
┃ ┃ ┃ ┣ components
┃ ┃ ┃ ┃ ┗ ArticleBox
┃ ┃ ┃ ┃ ┗ ArticleBox.tsx
┃ ┃ ┃ ┗ index.tsx
┃ ┃ ┣ Hero
┃ ┃ ┃ ┗ index.tsx
┃ ┗ index.tsx
┣ _app.css
┣ _app.tsx
┣ _document.tsx
┗ index.tsx
posts
┣ post_1.md
┣ post_2.md
┣ post_3.md
pages/blog/[slug].tsx
import { getAllPostIds, getPostData, getSortedPostsData } from '../../lib/posts';
import React from 'react';
import Hero from './Hero';
import BlogSection from './Blog';
export interface Props {
postData: {...},
posts: {...}[]
}
const BlogArticle: React.FC<Props> = ({ postData, posts }) => {
return (
<>
<Hero />
<BlogSection postData={postData} posts={posts} />
</>
);
};
export default BlogArticle;
export async function getStaticPaths() {
const paths = await getAllPostIds();
return {
paths,
fallback: false
}
}
export async function getStaticProps({ params }) {
return {
props: {
postData: await getPostData(params.slug),
posts: await getSortedPostsData()
}
}
}
lib/posts.js
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
const postsDirectory = path.join(process.cwd(), './posts')
export async function getSortedPostsData() {
const fileNames = fs.readdirSync(postsDirectory)
const allPostsData = fileNames.map(fileName => {
const slug = fileName.replace(/\.md$/, '')
const fullPath = path.join(postsDirectory, fileName)
const fileContents = fs.readFileSync(fullPath, 'utf8')
const matterResult = matter(fileContents)
return {
slug,
...matterResult.data
}
})
}
export async function getAllPostIds() {
const fileNames = fs.readdirSync(postsDirectory)
return fileNames.map(fileName => {
return {
params: {
slug: fileName.replace(/\.md$/, '')
}
}
})
}
export async function getPostData(slug) {
const fullPath = path.join(postsDirectory, `${slug}.md`)
const fileContents = fs.readFileSync(fullPath, 'utf8')
const { data: frontmatter, content } = matter(fileContents)
return {
slug,
content,
frontmatter
}
}
Thanks everyone!