首页 > 解决方案 > 如果该页面最终在渲染期间抛出,是否可以在构建期间跳过创建页面?

问题描述

如果该页面最终在渲染期间抛出,是否可以在构建期间跳过创建页面?

此页面是通过 gatsby-node 以编程方式创建createPage的,并且来自页面查询(来自我们的 CMS)的数据可能是错误的,导致它抛出。

我不想因为一个错误的页面而停止构建,所以理想情况下不会创建该页面或将后备页面放置在它的位置(并且错误事件将被记录到 Sentry 或类似的)。

关于如何实现这一目标的任何想法?


编辑:我没有充分澄清我的问题,所以我想添加一些关于我要解决的问题以及原因的背景信息。

我试图捕捉的错误发生在构建期间渲染页面的过程中。发生此错误是因为我尝试渲染的组件假定数据不正确(但应该是正确的)。

例如,假设我正在为我网站上的所有产品创建许多页面。该组件期望每个产品在渲染期间都有imagesSizes并调用。imagesSizes.split(',')因为imagesSizes来自页面查询null,所以整个组件会抛出错误并破坏构建。

就像@EliteRaceElephant 建议的那样,我尝试过使用React 错误边界,不幸的是,它们不适用于 SSR(Gatsby 在构建时使用)。因此,即使我将组件包装在错误边界中,它最终仍然会破坏构建。

最后一点,我上面给出的示例只是我遇到的数据错误并破坏构建的情况之一。

我想要实现的是一个简单的后备页面,用于在构建期间渲染期间发生任何任意错误时。当我对数据所做的某些假设不正确时,我的理想解决方案甚至允许我throw故意出错(因为我宁愿向用户发送错误页面,而不是向他们显示包含错误数据的页面)。


从历史上看,当我在 Gatsby 之外完成 SSR 时,我会简单地将整个调用包装ReactDOMServer.renderToString在一个try catch块中,然后在该块中返回我的后备页面catch

盖茨比相当于什么?

标签: gatsby

解决方案


您可以优雅地处理错误,因为 graphQL 查询是作为承诺返回的。如果承诺无法解决并继续构建您的页面,请处理引发的错误。

来自Gatsby 节点 API 文档

const path = require(`path`)
exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions
  const blogPostTemplate = path.resolve(`src/templates/blog-post.js`)

  return graphql(`
    query loadPagesQuery ($limit: Int!) {
      allMarkdownRemark(limit: $limit) {
        edges {
          node {
            frontmatter {
              slug
            }
          }
        }
      }
    }
  `, { limit: 1000 }).then(result => {
    if (result.errors) {
      throw result.errors

      // ##### Handle your ERROR here #######
      // send to sentry, try another query, etc
      // or pass an empty result object so no pages are created but the build continues

    }
    result.data.allMarkdownRemark.edges.forEach(edge => {
      createPage({
        path: `${edge.node.frontmatter.slug}`,
        component: blogPostTemplate,
        context: {},
      })
    })
  })
}

编辑#1

您的错误发生在页面模板中。您可以使用 React 方式处理组件中的错误,并带有错误边界。在你的组件周围包裹一个错误边界并处理那里的任何问题。错误边界也可以启动错误页面的构建。您也可以处理 PageTemplate 组件中返回的任何页面查询。

<PageTemplate>
  <ErrorBoundary>
    <YourContent />
  </ErrorBoundary>
</Page Template>

编辑#2

我现在了解这个问题,可以提供一些建议。我不认为有一个简单的解决方案,因为它涉及 React 和 Gatsby 的内部工作:

尝试捕获模板的非 React 部分。使用尝试捕获错误的包装函数。

我假设你的 JSX 代码中有这样的东西:

<PageTemplate>
  { imagesSizes.split(',') // do whatever and break the build }
</PageTemplate>

相反,请先通过 try catch 函数运行所有代码中断变量。如果有任何功能捕获,那么您将呈现您的错误页面。为此,您可能需要一个类基础组件。在调用之前放置函数render()

let pageThrows = false;

const imageSizesSplitCheck = (images) => {
  try {
    imagesSizes.split(',') // throw error
  } catch {
    pageThrows = true; // outside of the JSX flow you can still catch errors while serverside renddering
  }
}
// more try catch functions

if (pageThrows) {
  // render error page
} else {
  // render default page 
}


处理数据的边缘情况是一种很好的编码实践,这样就不会引发异常。我认为它甚至在清洁代码书中提到过。否则,您会误用正常程序流程的异常。例外应该仍然是例外。


推荐阅读