NextJS预呈现错误-在开发中工作正常,在构建中中断

olqngx59  于 2023-03-22  发布在  其他
关注(0)|答案(1)|浏览(196)

我正在构建一个NextJS应用程序,本地一切都运行良好。它拉入所有数据,没有抛出任何错误。
然而,当我尝试运行npm run build时,我得到一个Prerender错误。我已经尝试按照the documentation中的说明操作,但我发现它没有多大帮助。
问题是我使用path.join(process.cwd(), './posts')导入帖子,在这种情况下,当它构建时,路径与开发中的路径不同吗?我想不出还有什么可以遗漏的。
package.json

{
  ...
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  ....
}

完整错误:

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

下面是我的文件结构:

📦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
    }
}

谢谢大家!

nnsrf1az

nnsrf1az1#

感谢@TDiblik为我指明了正确的方向。正如他提到的,有一个good example from Vercel
我注意到我没有做的一件事是添加一种方法来处理post数据不可用的情况。在这种情况下,我需要在接收数据的每个页面/组件的默认导出中添加以下内容。

const router = useRouter()
    if (!router.isFallback && !post) {
        return <ErrorPage statusCode={404} />
    }

在本例中,我的pages/blog/[slug].tsx应该如下所示:

import { getAllPostIds, getPostData, getSortedPostsData } from '../../lib/posts';
import React from 'react';
import Hero from './Hero';
import BlogSection from './Blog';
import { useRouter } from 'next/router'
import ErrorPage from 'next/error'

export interface Props {
    postData: {...},
    posts: {...}[]
}

const BlogArticle: React.FC<Props> = ({ postData, posts }) => {
    const router = useRouter()
    if (!router.isFallback && !postData && !posts) {
        return <ErrorPage statusCode={404} />
    }
    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()
        }
    }
}

有了这个变化,我就能够构建这个项目了。
再次感谢托马斯!

相关问题