GAミント至上主義

Web Monomaniacal Developer.

(解決)NuxtJS + Composition APIでsetup()内でerror() 使うとDOMException: Failed to execute 'appendChild' on 'Node'

2021/9/7追記

エラーの原因は、@nuxtjs/composition-apiではなく、error.vueの描画時の問題だったので、error.vueの内容をclient-onlyで囲むことで解決しました!
@nuxtjs/composition-apiは悪くありませんでした。
ずっと放置してたけど他のメンバーに見てもらったら一瞬で解決できて感謝。



追記ここまで

表題で終わってるけど@nuxtjs/composition-apiを使ってsetup内でuseContextのerrorを使うとエラーから逃れられない。

バージョンはこんな感じ。

    "@nuxtjs/composition-api": "^0.24.6",
    "nuxt": "^2.15.7",

本番サーバー時、開発者ツールのconsoleを見ると下記エラーが出ていて、JSがストップしてしまうのでページ遷移などが不可能になる。

DOMException: Failed to execute 'appendChild' on 'Node': This node type does not support this method.

開発サーバー時はこのエラー

vue.runtime.esm.js?2b0e:619 [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.

SSR時にコンテンツが見つからないとき404レスポンスをしたくてがんばったけど無理だった。

もともとuseAsyncにメソッド内でerror() を使っていたけど調査のために下記のような最小限の構成を試したら同じ結果だった。

<script lang="ts">
import { defineComponent, useContext } from '@nuxtjs/composition-api'

export default defineComponent({
  // ダメ
  setup() {
    const { error } = useContext()
    error({ statusCode: 404 })
  }
  // 大丈夫
  asyncData({ error }) {
    return error({ statusCode: 404 })
  }
})

ひとまず、error404.vueという上記のasyncData形式で404を返すページを追加し、SSR時でコンテンツがないときは、そこにredirect() することにした。

useAsyncに渡すメソッド内

return $axios
        .$get<ApiResponse>('/api/list')
        .catch(e => {
          // CSR 時はこれでエラーページ出る
          error({
            statusCode: e.response.status,
            message: 'エラーが発生しました'
          })
          // SSR時に下記エラーが起きて、動かなくなってしまうため暫定処理
          // DOMException: Failed to execute 'appendChild' on 'Node': This node type does not support this method.
          if (process.server && e.response.status === 404) {
            redirect('/error404')
          }
        })

Nuxt本体のソースコードも見たけど複雑すぎるし、現在、近々Vue3版が出るという過渡期だと思うので今回はこれで妥協。