Dec 21, 2020

Nuxtで作成したこのブログをSEO対応してみた。

Nuxt で作成したこのブログを SEO 対応してみました。sitemap や robots の他に動的ページに合わせて feed や meta 情報などを埋め込みたいと思います。このホームページは個人的な備忘録、記事を書き留めているだけなので、検索数を伸ばしたいとかはないですが、動的ページのホームページで SEO 対応どこまでできるかやってみました。

Sitemap を作りたいと思います。

ゼロから作らなくてもモジュールが用意されているんですね。@nuxtjs/sitemapをインストールして、nuxt.config.js ファイルにスクリプト追加すれば良さそうです。

  yarn add @nuxtjs/sitemap
    :

次に nuxt.config.js ファイルを修正していきたいと思います。モジュールを追加して、スクリプトでは、sitemap に情報を設定すれば良さそうです。path には sitmap の URL を設定して、routes にページの情報をを設定すればいいようです。今回は記事一覧の情報をセットしたいと思います。content ファイルを読み込んで設定しています。url にページのパスを設定して lastmod に記事の更新日を設定しました。changefreq も日付に応じてつけられそうですが今回は割愛。priority も固定です。

nuxt.config.js
  export default {
      :
    modules: [
    "@nuxt/content",
    "@nuxtjs/sitemap",
    ],
    sitemap: {
      path: '/sitemap.xml',
      hostname: 'https://www.akiboi.duckdns.org',
      routes: async () => {
        const { $content } = require('@nuxt/content')
        const articles = await $content('articles').only(['path','updatedAt']).fetch()
        return articles.map((article) => ({
          url:article.path,
          priority: 0.8,
          lastmod: article.updatedAt,
          }))
        }
    },
    :
  }

/sitemap.xml にアクセスし sitemap の XML が表示されれば完了です。

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" ...
    <url>
        <loc>https://www.akiboi.duckdns.org/articles/about</loc>
        <lastmod>2020-12-20T02:50:13.000Z</lastmod>
        <priority>0.8</priority>
    </url>
    <url>
        <loc>https://www.akiboi.duckdns.org/articles/alex</loc>
        <lastmod>2020-08-07T12:40:00.000Z</lastmod>
        <priority>0.8</priority>
    </url>
      :
</urlset>

feed を追加したいと思います。

feed もモジュール@nuxtjs/feedが用意されていました。こちらも同じように作成してみました。rss と json タイプの二種類出力できるようにしています。

  yarn add @nuxtjs/feed
    :
nuxt.config.js
  export default {
      :
    modules: [
    "@nuxt/content",
    "@nuxtjs/sitemap",
    "@nuxtjs/feed",
    ],
      :
  feed() {
    const baseUrlArticles = 'https://www.akiboi.duckdns.org/blog'
    const baseLinkFeedArticles = '/feed'
    const feedFormats = {
      rss: { type: 'rss2', file: 'rss.xml' },
      json: { type: 'json1', file: 'feed.json' },
      atom: { type:'atom1',file:'feed.xml'}
    }
    const { $content } = require('@nuxt/content')
    const createFeedArticles = async function (feed) {
      feed.options = {
        title: 'Akiboi Blog',
        description: '自宅にサーバを作ろう',
        link: baseUrlArticles,
      }
      const articles = await $content('articles')
        .only(['title','description','updatedAt'])
        .sortBy('updatedAt','desc')
        .limit(20)
        .fetch()
      articles.forEach((article) => {
        const url = `${baseUrlArticles}/${article.slug}`
        feed.addItem({
          title: article.title,
          id: url,
          link: url,
          date: new Date(article.updatedAt),
          description: article.description,
        })
      })
    }
    return Object.values(feedFormats).map(({ file, type }) => ({
      path: `${baseLinkFeedArticles}/${file}`,
      type: type,
      create: createFeedArticles,
    }))
  },
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
    <channel>
        <title>Akiboi Blog</title>
        <link>https://www.akiboi.duckdns.org/blog</link>
        <description>自宅にサーバを作ろう</description>
        <lastBuildDate>Sun, 20 Dec 2020 09:17:33 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/nuxt-community/feed-module</generator>
        <item>
            <title>
                <![CDATA[自宅にサーバを作ろう !!]]>
            </title>
            <link>https://www.akiboi.duckdns.org/blog/about</link>
            <guid>https://www.akiboi.duckdns.org/blog/about</guid>
        </item>
          :

ついでに robots.txt もモジュールがあったので@nuxtjs/robotsを追加しました。

  yarn add @nuxtjs/robots
    :
nuxt.config.js
  export default {
      :
    modules: [
    "@nuxt/content",
    "@nuxtjs/sitemap",
    "@nuxtjs/feed",
    "@nuxtjs/robots",
    ],
      :
  robots: {
    UserAgent: '*',
    Sitemap: 'https://www.akiboi.duckdns.org/sitemap.xml',
  },
https://www.akiboi.duckdns.org/robots.txt
User-agent: *
Disallow:
Sitemap: https://www.akiboi.duckdns.org/sitemap.xml

Nuxt の動的ページにメタタグを追加してみた。

Nuxt の動的ページ毎にメタタグを入れたいと思います。nuxt.config.js のヘッダ情報に記載することもできるようですが、動的ページ毎に適切なメタタグを設定できるように composition-api のuseMetaを利用したいと思います。

記事を読み込んだタイミングで記事の情報からタイトルなどの情報を取得してセットしたいと思います。最初に composition-api で記載したコンポーネント Article.Vue に head:を追加します。メタタグは、前回作成した contentCtl.tsに追加したいと思います。

/components/Article.Vue
<template>
  :
</template>
 
<script lang="ts">
import { defineComponent, useContext } from '@nuxtjs/composition-api';
import { contentCtl } from '@/composables/contentCtl.ts';
export default defineComponent({
  head: {},
  setup() {
    const { params } = useContext();
    const { article, getArticle } = contentCtl();
    getArticle(params.value.slug);
    return {
      article,
    };
  },
});
</script>

記事に合わせたメタタグを設定したいと思いますので、前回作成した contentCtl 内にメタタグ情報を追加するコードを書きたいと思います。useMeta()の title と meta にそれぞれ記事に記載しているフロントマターから情報をとって設定したいと思います。

/composables/contentCtl.ts
import { reactive, computed, useContext, useMeta } from '@nuxtjs/composition-api';
const contentCtl = () => {
  const state = reactive({
    articles: [] as Object,
    article: {} as IContentDocument,
  });
  const articles = computed(() => state.articles);
  const article = computed(() => state.article);
  const { $content } = useContext();
  const { title, meta } = useMeta();
  async function getArticle(slug: string) {
    state.article = await $content('articles'), slug).fetch();
    title.value = state.article.title;
    meta.value = getMeta(state.article.title, state.article.description, slug, state.article.img);
  }
  function getMeta(title: string, description: string, slug: string, img: string) {
    const baseURL = 'https://www.akiboi.duckdns.org';
    const meta = [
      { hid: 'description', name: 'description', content: description },
      { hid: 'og:title', property: 'og:title', content: title },
      { hid: 'og:type', property: 'og:type', content: 'article' },
      { hid: 'og:description', property: 'og:description', content: description },
      { hid: 'og:image', property: 'og:image', content: baseURL + img },
      { hid: 'og:url', property: 'og:url', content: baseURL + '/' + slug },
      { hid: 'og:locale', property: 'og:locale', content: 'ja_JP' },
      { hid: 'og:site_name', property: 'og:site_name', content: 'akiboi Blog' },
      { hid: 'twitter:card', name: 'twitter:card', content: 'summary' },
      { hid: 'twitter:site', name: 'twitter:site', content: '@akibo_I' },
      { hid: 'twitter:title', name: 'twitter:title', content: title },
      { hid: 'twitter:description', name: 'twitter:description', content: description },
      { hid: 'twitter:image', name: 'twitter:image', content: baseURL + img },
    ];
    return meta;
  }

今回のメタタグは、HTML Meta,Facebook Open Graph,Twitter Cards を設定しました。 Chrom のアドオン meta Tag Analyzer で確認しました。

meta Tag Analyzer!

また、twitter でホームページの URL を貼り付けたら以下のように twitter Cards が付きました。

twitter Cards!