[Vue3] SEO対策してみる

あんまりよく分かってはいないけどSEO対策としてtitleとかdescriptionとかを設定する。
SPAなのでheadに埋め込めないよねっていう悩みを解消します。まずはこちらを入れます。

@unhead/vue
Latest version: 1.11.18, last published: 10 days ago. Start using @unhead/vue in your project by running `npm i @unhead/vue`. There are 69 other projects in the...
yarn add @unhead/vue

app.tsに加えます

import './bootstrap'
import { createApp } from 'vue'
import App from '../App.vue'
import router from '../router/index'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import '@/bootstrap/css/bootstrap.min.css'
import { createHead } from '@unhead/vue'

const app = createApp(App)

app.use(router)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
app.use(createHead())
app.mount('#app')

config/seo.tsに設定ファイルを書きました

export const SEO = {
  DEFAULT: { title: 'DayByDay', description: 'DayByDayの技術ブログです', keywords: 'DayByDay、プログラミング' },
  Root: { title: 'DayByDay Top', description: 'DayByDayの技術ブログです。', keywords: 'DayByDay、プログラミング' },
  Top: { title: 'DayByDay Top', description: 'DayByDayの技術ブログです', keywords: 'DayByDay、プログラミング' },
  Search: { title: 'DayByDay 検索', description: 'DayByDayの技術ブログの記事を検索できます', keywords: 'DayByDay、プログラミング、Vue、composition' },
}

これを呼び出すためのUtilメソッドを作成しますutil.tsに入れました

import { SEO } from '@/config/seo'
import { useHead } from '@unhead/vue'

export function setSeo (page?: string): void {
  if (page !== undefined && page !== null && SEO[page] !== undefined) {
    useHead({
      title: () => SEO[page].title,
      meta: [
        {
          name: 'description',
          content: SEO[page].description
        },
        {
          name: 'keywords',
          content: SEO[page].keywords
        }
      ]
    })
  } else {
    useHead({
      title: () => SEO.DEFAULT.title,
      meta: [
        {
          name: 'description',
          content: SEO.DEFAULT.description
        },
        {
          name: 'keywords',
          content: SEO.DEFAULT.keywords
        }
      ]
    })
  }
}

さらにこれに渡すために各ページで書いてもよいのですがめんどくさいのでrouterに任せました。vue-routerに付け加えます。router/index.tsに

import { setSeo } from '@/js/util'
// 色々書いてる
const routes = [
  { path: '/', name: 'Root', component: Top},
]


const router = createRouter({
  routes,
  history: createWebHistory(),
  scrollBehavior (to, from, savedPosition) {
    if (savedPosition) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(savedPosition)
        })
      })
    } else {
      return { left: 0, top: 0 }
    }
  }
})

// 読み込まれる時に設定を読み込んで
router.beforeEach((to, from, next) => {
  setSeo(to.name?.toString())
})
export default router

こんな感じでrouterのroutesのnameに合わせて設定ファイルの連想配列を読み込ませます。これで各ページで読む手間が省けました!
しかし、ブログのタイトルは記事によって変わるのでもう少し動的にします。対象のページに追加します

<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'
import { SEO } from '@/config/seo'
import { useHead } from '@unhead/vue'
const seoTitle = ref<string>('')
const route = useRoute()
watch(
  () => route.name,
  (newRouteName) => {
    if (newRouteName && SEO[newRouteName]) {
      useHead({
        title: () => SEO[newRouteName].title.replace('ブログタイトル', seoTitle.value),
        meta: [
          {
            name: 'description',
            content: SEO[newRouteName].description,
          },
          {
            name: 'keywords',
            content: SEO[newRouteName].keywords,
          },
        ],
      })
    }
  },
  { immediate: true }
)
</script>

こんな感じで各ページでのtitleやdiscriptionを反映させました

コメント

タイトルとURLをコピーしました