ヘッダのタイトルが表示されないのと、エラーページがデフォルトのままになってしまったので、そちらの修正を行います。
前回:Nuxt BridgeをNuxt3に移行。ESlintを導入

ヘッダのタイトルが表示されない

Migrate to Nuxt 3: Meta Tags

Options APIの記法

defineNuxtComponentが必要
// if using options API `head` method you must use `defineNuxtComponent`

そもそもdefineNuxtComponentで囲ってあげないと、headが認識しない。
layouts, pages, components, Mixinで使っているutils等、序でに全部変更しておきます。

<script>
- export default {
+ export default defineNuxtComponent({

- }
+ })
</script>
コンポーネントインスタンスにアクセスできない
// `head` receives the nuxt app but cannot access the component instance

localやconfigを使っている場合は自分で対応する必要があります。

Uncaught (in promise) TypeError: this.$t is not a function
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'public')

例: layouts/default.vue

  head () {
+    const { t: $t } = useI18n()
+    const $config = useRuntimeConfig()
    return {
-      titleTemplate: `%s - ${this.$t('app_name')}${this.$config.public.envName}`
+      titleTemplate: `%s - ${$t('app_name')}${$config.public.envName}`
    }
  },

titleも同様ですが、次のBuilt-in Meta-componentsを使うのも良さそう。

Built-in Meta-components

Composition API書き換え前ですが、<template>内に定義できるので、先頭にあると解りやすい。

但し、TitleTemplateは対応していないのが残念だけど、TitleやMetaは入れやすい。
[Vue warn]: Failed to resolve component: TitleTemplate

例: pages/infomations/index.vue

<template>
+  <Head>
+    <Title>お知らせ</Title>
+  </Head>

export default defineNuxtComponent({
-  head () {
-    return {
-      title: 'お知らせ'
-    }
-  },

Built-in Meta-componentsで動的な値

computed等で値を渡してあげれば、普通に使えます。

例: pages/infomations/[id].vue

<template>
+  <Head>
+    <Title>{{ title }}</Title>
+  </Head>

export default defineNuxtComponent({
-  head () {
-    return {
-      title: this.title
-    }
-  },
-
  computed: {
    title () {
      let label = ''
      if (this.infomation?.label_i18n != null && this.infomation?.label_i18n !== '') {
        label = `[${this.infomation.label_i18n}]`
      }
      return label + (this.infomation?.title || '')
    }
  },

漏れがないか確認

before(nuxt2): nuxt.config.js
  // Global page headers: https://go.nuxtjs.dev/config-head
  head: {
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },

何も設定しなくても、charsetとviewportは入っていました。
SEO and Meta · Get Started with Nuxt

faviconはデフォルトのなので、なくても問題ない。

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

エラーページをカスタマイズする

Error handling · Get Started with Nuxt

error.vue

layouts/error.vueは不要になったので削除します。
せっかくなので、Composition API+TypeScriptで書き直します。

<template>
  <NuxtLayout>
    <Head>
      <Title>{{ title }}</Title>
      <Meta name="robots" content="noindex" />
    </Head>
    <v-card>
      <v-card-title>{{ alertMessage }}</v-card-title>
      <v-card-text v-if="noticeMessage != null">{{ noticeMessage }}</v-card-text>
      <v-card-actions>
        <NuxtLink to="/">トップページ</NuxtLink>
      </v-card-actions>
    </v-card>
  </NuxtLayout>
</template>

<script setup lang="ts">
const { t: $t } = useI18n()
const props = defineProps({
  // eslint-disable-next-line vue/require-default-prop
  error: Object
})

const title = computed(() => (props.error?.statusCode === 404) ? 'Not Found' : 'エラー')
const alertMessage = computed(() => {
  if (props.error?.data?.alert != null) { return props.error.data.alert }
  return $t((props.error?.statusCode === 404) ? 'system.notfound' : 'system.default')
})
const noticeMessage = computed(() => props.error?.data?.notice)
</script>

(削除前の)layouts/error.vue

参考までに、Nuxt2の時のOptions APIで書いたコードです。
Composition API(上のコード)の方がスッキリしていますね。

<template>
  <div>
    <v-card>
      <v-card-title>{{ alertMessage }}</v-card-title>
      <v-card-text v-if="error.notice != null">{{ error.notice }}</v-card-text>
      <v-card-actions>
        <NuxtLink to="/">トップページ</NuxtLink>
      </v-card-actions>
    </v-card>
  </div>
</template>

<script>
export default {
  props: {
    error: {
      type: Object,
      default: null
    }
  },

  head () {
    return {
      title: (this.error.statusCode === 404) ? 'Not Found' : 'エラー'
    }
  },

  computed: {
    alertMessage () {
      if (this.error.alert == null) {
        return this.$t((this.error.statusCode === 404) ? 'system.notfound' : 'system.default')
      }

      return this.error.alert
    }
  },

  created () {
    // eslint-disable-next-line no-console
    if (this.$config.public.debug) { console.dir(this.error) }
  }
}
</script>

動作確認

404の場合

404以外で、APIからのメッセージがない場合

存在しないメソッドを入れてみる
  created () {
+    xxx

画面は真っ白

Uncaught (in promise) ReferenceError: xxx is not defined

Nuxt3入門(第6回) – アプリケーションで発生するエラーに対応する | 豆蔵デベロッパーサイト

クライアントサイドで例外をスローするとデフォルトは非クリティカルなエラーになり、
エラーページは表示されません。
明示的にエラーページを表示する場合は、showErrorまたは、createErrorの引数でfatalをtrue

つまりブラウザ上でエラーになった場合、画面表示は変わらない。
なので、これでも結果は同じです。

+    throw 'エラー'
+    throw createError('エラー')
showErrorを呼び出してみる
  created () {
+    throw showError({ statusCode: 500, message: 'サーバーエラー' })
Uncaught (in promise) Error: サーバーエラー

APIからのメッセージがある場合

  created () {
+    throw showError({ statusCode: 500, message: 'サーバーエラー', data: { alert: 'エラーメッセージ', notice: '追加情報' } })
Uncaught (in promise) Error: サーバーエラー

TypeError: this.$nuxt.error is not a function

$nuxt.errorがなくなっているので、throw showErrorに変更します。

例: utils/application.js

-      this.$nuxt.error({ statusCode, alert: data.alert, notice: data.notice })
+      throw showError({ statusCode, data: { alert: data.alert, notice: data.notice } })

package.jsonとnuxt.config.ts(.js)の新旧を比較して、漏れがない事を確認。
PWAは使ってなかったので導入しない。Vuetifyの移行していない設定が残っている。

残りはデザイン崩れ(Vuetify)と、テスト(Vitest)の導入と既存テスト(Jest)の移行です。
いよいよ終わりが見えてきましたが、それぞれ修正量が多そうな予感がします。
Nuxt BridgeをNuxt3に移行。Vuetify3のテーマと色を設定+確認ページ作成

今回のコミット内容

origin#507 ヘッダタイトルとエラーページを修正

Nuxt BridgeをNuxt3に移行。ヘッダタイトルとエラーページを修正” に対して1件のコメントがあります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です