[Next.js]Incremental Static Regenerationのデプロイで出たエラーと解決法

2 min読了の目安(約2300字TECH技術記事

SSGだと(正確にはgetStatiPathsの返り値fallback:falseにした時)にエラーが出てなかなか困ったので備忘録もかねて共有します

TypeError: Only absolute URLs are supported

fetchのurlが絶対パスになってないというエラーです。client側で使うときは /api/postsで大丈夫なんですが、 getStaticPaths、getStaticProps側ではエラーになってしまいます

export const getStaticProps = async (ctx) => {
  try {
    const result = await fetch(`https://foo.com/api/posts/${ctx.params.id}`)
    const post = await result.json()
    return {
      props: { post },
      revalidate: 60,
    }
  } catch (e) {
    console.log({ e })
  }
}

Error: Invalid value returned from getStaticPaths in YOUR PATH. Received undefined Expected: { paths: [], fallback: boolean }

getStaticPathsの返り値にpathsが入ってない場合に出たエラーです。fetchがうまくできてなくデータが取得できてませんでした。ローカルでは大丈夫な場合は本番のURLやapiサーバーのURLをチェックするといいかもしれません

特に今回はvercel使ってたのでdeploymentのurlが毎回変わるので困惑しました。
最初は VERCEL_URL使って動的にドメインを取得していましたが、どうもうまくいかなかったので最終的には環境変数にdeployしたドメインを登録することで解決しました。

//localの.env
WEBAPP_URL="http://localhost:3000"

//vercelのEnvironment Variables
WEBAPP_URL="https://foo.vercel.app"
fetch(`${process.env.WEBAPP_URL}/api/${url}`).then((res) => res.json())

TypeError: Cannot read property '_id' of undefined

mongoDBを使用していたのでそこ周りだと疑って_id使ってる箇所を一つずつコメントアウトしてみながら調査しました。結果的にはreact-query(多分swrでも同様かと)でgetStaticPropsから受け取ったpropsを使っていたのが原因だったようです。

export const getStaticPaths = async () => {
  try {
    const posts = await getData('posts')
    const paths = await posts.map((post: postProps) => `/posts/${post._id}`)
    return {
      paths,
      fallback: true,
    }
  } catch (e) {
    console.log({ e })
  }
}
export const getStaticProps = async (ctx) => {
  try {
    const post = await getData(`posts/${ctx.params.id}`)
    return {
      props: { post },
      revalidate: 60,
    }
  } catch (e) {
    console.log({ e })
  }
}

const Page: NextPage = (props) => {
  const router = useRouter()
  const { data: post } = useQuery(`posts/${props.post._id}`, getData, {
    initialData: props.post,
  })//問題の箇所

  if (router.isFallback) {
    return <div>Loading...</div>
  }

  return <p>{post.title}</p>
}

export default Page

ssgするのでそもそもcache持っておく必要もないのかなと思い、問題の箇所を消去して調整したらdeployできました。

またrouterからidを取ってくる方法でも良さそうでした。

const { data: post } = useQuery(`posts/${router.query.id}`, getData, {
    initialData: props.post,
  }) 

以上です、参考になれば幸いです。
エラー出まくってもNext.js楽しい!