在 npm 运行 build 中的预呈现页面上获取 TypeError
Getting TypeError on prerendering page in npm run build
我正在我的 Next.js 应用程序中预呈现此页面:
const router = useRouter();
if (!router.isFallback && !postData?.slug) {
return <p>hmm... looks like an error</p>
}
const formatDate = date => {
const newDate = new Date(date);
return `${newDate.getDate()}/${
newDate.getMonth() + 1
}/${newDate.getFullYear()}`
};
return (
<div className={styles.container}>
<Head>
<title>{postData.title}</title>
<link rel='icon' href='/favicon.ico' />
</Head>
<main className={styles.main}>
{router.isFallback ? (
<h2>Loading...</h2>
) : (
<article className={blogStyles.article}>
<div className={blogStyles.postmeta}>
<h1 className={styles.title}>{postData.title}</h1>
<p>{formatDate(postData.date)}</p>
<img src={postData.featuredImage.node.sourceUrl} />
</div>
<div
className='post-content content'
dangerouslySetInnerHTML={{ __html: postData.content }}
/>
</article>
)}
<p>
<Link href={`/blog`}>
<a>Back</a>
</Link>
</p>
</main>
</div>
)
使用getStaticProps()
export async function getStaticProps({ params }) {
const data = await getPost(params.slug);
return {
props: {
postData: data.post
}
};
}
使用getStaticPaths()
export async function getStaticPaths() {
const allPosts = await getAllPostsWithSlug();
if (
allPosts &&
allPosts.edges !== null &&
allPosts.edges.node !== null &&
allPosts.edges.length > 0
) {
return {
paths: allPosts.edges.map(({ node }) => `/blog/${node.slug}`) || [],
fallback: true
}
}
}
当我 运行 它在本地工作正常但是当我尝试使用 npm run build
部署它时它仅针对 title
属性 给出错误:
Error occurred prerendering page "/blog/[slug]". Read more: https://err.sh/next.js/prerender-error
TypeError: Cannot read property 'title' of undefined
这是让我感到困惑的部分,因为我不明白为什么错误仅出现在查询的 1 属性 (postData.title) 上,而其他所有内容都加载正常。
我正在使用 GraphQL 创建查询:
export async function getPost(slug) {
const data = await fetchAPI(
`
fragment PostFields on Post {
title
excerpt
slug
date
featuredImage {
node {
sourceUrl
}
}
}
query PostBySlug($id: ID!, $idType: PostIdType!) {
post(id: $id, idType: $idType) {
...PostFields
content
}
}
`,
{
variables: {
id: slug,
idType: 'SLUG'
}
}
);
return data;
}
我通过 api.js 文件导入此函数,并在 getStaticProps() 函数中使用数据。
非常感谢对此的任何帮助,我在网上寻找解决方案但找不到任何有效的解决方案。谢谢!
在处理诸如 /blog/[slug].jsx
之类的动态页面时,除了 getStaticProps
和 router.isFallback?
之外,您还需要使用 getStaticPaths
,就像您在上面返回的 jsx 中使用的那样.
getStaticPaths
catches incoming possible paths -- 但是它的行为取决于 fallback
键(它的值可以是 true
、false
或 "blocking"
)
Blocking
与服务器端呈现相同,因此它根据需要为 getStaticPaths
未返回的路径生成静态 HTML。这被缓存以供将来使用,因此这种按需生成只在每个未被您的 getStaticPaths
函数处理的路径发生一次。如果将 getStaticPaths
设置为 true
,那么一小部分动态路径将在构建时呈现,如果用户导航到的路径在初始阶段未呈现,则会向用户显示加载指示器建造。使用 true
对于大型电子商务站点或具有大量动态路径的站点很有用,这样构建过程就不会花费很长时间才能完成。将 getStaticPaths
设置为 false
将导致在构建过程中不呈现任何路径,如果用户导航到它会导致 404 错误。根据您的需要,上述任何一种方法都可能是最合适的。也就是说,重要的是要注意 "blocking"
根本不需要使用 router.isFallback
。我还建议研究使用 revalidate
和 getStaticProps
的好处。
下面是使用 getStaticPaths
捕获传入动态路径的示例:
const AboutSlugsQueryVars: AboutSlugsVariables = {
order: OrderEnum.ASC,
field: PostObjectsConnectionOrderbyEnum.SLUG,
first: 15
};
type DynamicPaths = {
params:
| {
slug: string | Array<string>;
}
| never[];
}[];
export async function getStaticPaths(
ctx: GetStaticPathsContext,
pathsData: DynamicPaths
) {
const q = ctx!.defaultLocale;
console.log(`${q}`)
const apolloClient = initializeApollo();
const { data } = await apolloClient.query<AboutSlugs, AboutSlugsVariables>({
query: ABOUT_SLUGS,
variables: AboutSlugsQueryVars
});
pathsData = [];
if (
data &&
data.aboutslugs !== null &&
data.aboutslugs.edges !== null &&
data.aboutslugs.edges.length > 0
)
data.aboutslugs.edges.map(post => {
if (post !== null && post.node !== null && post.node.slug !== null) {
pathsData.push({ params: { slug: post.node.slug } });
}
});
return {
paths: pathsData,
fallback: true
};
}
过滤 getStaticPaths
的方法有很多,您也可以使用 GetStaticPathsContext
来捕获传入的 locales
以及默认的 locale
(如果适用)。
如果有人在使用 yarn export
时遇到此问题或类似问题,解决方案是将回退设置为 false。这为我修复了所有页面呈现错误。
来自 Next.js 文档:
// This function gets called at build time
export async function getStaticPaths() {
// Call an external API endpoint to get posts
const res = await fetch('https://.../posts')
const posts = await res.json()
// Get the paths we want to pre-render based on posts
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false }
}
我正在我的 Next.js 应用程序中预呈现此页面:
const router = useRouter();
if (!router.isFallback && !postData?.slug) {
return <p>hmm... looks like an error</p>
}
const formatDate = date => {
const newDate = new Date(date);
return `${newDate.getDate()}/${
newDate.getMonth() + 1
}/${newDate.getFullYear()}`
};
return (
<div className={styles.container}>
<Head>
<title>{postData.title}</title>
<link rel='icon' href='/favicon.ico' />
</Head>
<main className={styles.main}>
{router.isFallback ? (
<h2>Loading...</h2>
) : (
<article className={blogStyles.article}>
<div className={blogStyles.postmeta}>
<h1 className={styles.title}>{postData.title}</h1>
<p>{formatDate(postData.date)}</p>
<img src={postData.featuredImage.node.sourceUrl} />
</div>
<div
className='post-content content'
dangerouslySetInnerHTML={{ __html: postData.content }}
/>
</article>
)}
<p>
<Link href={`/blog`}>
<a>Back</a>
</Link>
</p>
</main>
</div>
)
使用getStaticProps()
export async function getStaticProps({ params }) {
const data = await getPost(params.slug);
return {
props: {
postData: data.post
}
};
}
使用getStaticPaths()
export async function getStaticPaths() {
const allPosts = await getAllPostsWithSlug();
if (
allPosts &&
allPosts.edges !== null &&
allPosts.edges.node !== null &&
allPosts.edges.length > 0
) {
return {
paths: allPosts.edges.map(({ node }) => `/blog/${node.slug}`) || [],
fallback: true
}
}
}
当我 运行 它在本地工作正常但是当我尝试使用 npm run build
部署它时它仅针对 title
属性 给出错误:
Error occurred prerendering page "/blog/[slug]". Read more: https://err.sh/next.js/prerender-error
TypeError: Cannot read property 'title' of undefined
这是让我感到困惑的部分,因为我不明白为什么错误仅出现在查询的 1 属性 (postData.title) 上,而其他所有内容都加载正常。
我正在使用 GraphQL 创建查询:
export async function getPost(slug) {
const data = await fetchAPI(
`
fragment PostFields on Post {
title
excerpt
slug
date
featuredImage {
node {
sourceUrl
}
}
}
query PostBySlug($id: ID!, $idType: PostIdType!) {
post(id: $id, idType: $idType) {
...PostFields
content
}
}
`,
{
variables: {
id: slug,
idType: 'SLUG'
}
}
);
return data;
}
我通过 api.js 文件导入此函数,并在 getStaticProps() 函数中使用数据。
非常感谢对此的任何帮助,我在网上寻找解决方案但找不到任何有效的解决方案。谢谢!
在处理诸如 /blog/[slug].jsx
之类的动态页面时,除了 getStaticProps
和 router.isFallback?
之外,您还需要使用 getStaticPaths
,就像您在上面返回的 jsx 中使用的那样.
getStaticPaths
catches incoming possible paths -- 但是它的行为取决于 fallback
键(它的值可以是 true
、false
或 "blocking"
)
Blocking
与服务器端呈现相同,因此它根据需要为 getStaticPaths
未返回的路径生成静态 HTML。这被缓存以供将来使用,因此这种按需生成只在每个未被您的 getStaticPaths
函数处理的路径发生一次。如果将 getStaticPaths
设置为 true
,那么一小部分动态路径将在构建时呈现,如果用户导航到的路径在初始阶段未呈现,则会向用户显示加载指示器建造。使用 true
对于大型电子商务站点或具有大量动态路径的站点很有用,这样构建过程就不会花费很长时间才能完成。将 getStaticPaths
设置为 false
将导致在构建过程中不呈现任何路径,如果用户导航到它会导致 404 错误。根据您的需要,上述任何一种方法都可能是最合适的。也就是说,重要的是要注意 "blocking"
根本不需要使用 router.isFallback
。我还建议研究使用 revalidate
和 getStaticProps
的好处。
下面是使用 getStaticPaths
捕获传入动态路径的示例:
const AboutSlugsQueryVars: AboutSlugsVariables = {
order: OrderEnum.ASC,
field: PostObjectsConnectionOrderbyEnum.SLUG,
first: 15
};
type DynamicPaths = {
params:
| {
slug: string | Array<string>;
}
| never[];
}[];
export async function getStaticPaths(
ctx: GetStaticPathsContext,
pathsData: DynamicPaths
) {
const q = ctx!.defaultLocale;
console.log(`${q}`)
const apolloClient = initializeApollo();
const { data } = await apolloClient.query<AboutSlugs, AboutSlugsVariables>({
query: ABOUT_SLUGS,
variables: AboutSlugsQueryVars
});
pathsData = [];
if (
data &&
data.aboutslugs !== null &&
data.aboutslugs.edges !== null &&
data.aboutslugs.edges.length > 0
)
data.aboutslugs.edges.map(post => {
if (post !== null && post.node !== null && post.node.slug !== null) {
pathsData.push({ params: { slug: post.node.slug } });
}
});
return {
paths: pathsData,
fallback: true
};
}
过滤 getStaticPaths
的方法有很多,您也可以使用 GetStaticPathsContext
来捕获传入的 locales
以及默认的 locale
(如果适用)。
如果有人在使用 yarn export
时遇到此问题或类似问题,解决方案是将回退设置为 false。这为我修复了所有页面呈现错误。
来自 Next.js 文档:
// This function gets called at build time
export async function getStaticPaths() {
// Call an external API endpoint to get posts
const res = await fetch('https://.../posts')
const posts = await res.json()
// Get the paths we want to pre-render based on posts
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false }
}