SvelteでSEOのメタデータを管理する方法

# はじめに
本記事ではSvelteプロジェクトで主にSEOに必要なメタデータを管理する方法について説明していきます。
[svelte-meta-tags](https://github.com/oekazuma/svelte-meta-tags)というライブラリを使用することが前提の記事ですのでその点、ご了承ください。

[デモはこちら](https://svelte.dev/repl/ffd783c9b8e54d97b6b7cac6eadace42?version=3.43.1)

# インストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217487/26b3b364-983a-474a-5ad9-55cb04e56d8a.png)

[svelte-meta-tags](https://github.com/oekazuma/svelte-meta-tags)をSvelteプロジェクトにインストールします。

```shell
npm install svelte-meta-tags
```

または


```shell
yarn add svelte-meta-tags
```

# 使い方
インストールが完了したら、早速使っていきます。

Svelteを使ってWebサイトを構築する上で何かしらのルーターライブラリを使用して構築している方が多いと思います。
それぞれページにあたるファイルに書いていきましょう。
このライブラリは[SvelteKit](https://kit.svelte.dev/)や[Routify](https://routify.dev/)といった主要なライブラリに対応しています。

```html
<script>
  import { MetaTags } from 'svelte-meta-tags';
</script>

<MetaTags title="タイトル" description="ディスクリプション" />
```

上記のように書くと`<head/>`タグ内に以下のようにレンダリングされます。

```html
<title>タイトル</title>
<meta name="robots" content="index,follow">
<meta name="googlebot" content="index,follow">
<meta name="description" content="ディスクリプション">
```

`<MetaTags/>`コンポーネントは複数のプロパティを持っていて、それらを活用することで簡単に`<head/>`タグ内にメタデータを追加することができます。

## 主なプロパティ

| プロパティ                        | 型                    | 詳細                                                                                                                            |
| ---------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `title`                            | string                  | ページのメタタイトルを設定します。                                                                                                             |
| `noindex`                          | boolean (default false) | ページをインデックスに登録するかどうかを設定します。                                                                                             |
| `nofollow`                         | boolean (default false) | ページをフォローするかどうかの設定します。                                                                                            |
| `additionRobotsProps`              | Object                  | `X-Robots-Tag`のメタデータを設定します。                                                        |
| `description`                      | string                  | ページのメタディスクリプションを設定します。                                                                                                       |
| `canonical`                        | string                  | ページのcanonical urlを設定します。                                                                                                          |
| `mobileAlternate.media`            | string                  | どの画面サイズからモバイルサイトを提供するかを設定します。                                                                        |
| `mobileAlternate.href`             | string                  | モバイルページの代替URLの設定します。                                                                                                  |
| `languageAlternates`               | array                   | 代替URLの言語を設定します。以下のようなオブジェクトの配列を想定しています。`{ hrefLang: string, href: string }`               |
| `additionalMetaTags`               | array                   | ここに記載されていないメタタグを追加することができます。                                       |
| `additionalLinkTags`               | array                   | ここに記載されていないリンクタグを追加することができます。                                        |
| `twitter.cardType`                 | string                  | カードの種類で、`summary`, `summary_large_image`, `app`, `player` のいずれかになります。                                              |
| `twitter.site`                     | string                  | カードのフッターに使用されるウェブサイトの@ユーザー名                                                                              |
| `twitter.handle`                   | string                  | コンテンツ作成者/著者の@ユーザー名（`twitter:creator`として出力されます。)                                                            |
| `facebook.appId`                   | string                  | Facebookのインサイトに使用されるため、FacebookアプリのIDをページに追加する必要があります。                                                     |                                                                                             

すべてのプロパティや使い方を詳しく確認したい場合は[こちら](https://github.com/oekazuma/svelte-meta-tags#properties)から確認してください。
## OGPを設定する

```js
<script>
  import { MetaTags } from 'svelte-meta-tags';
</script>

<MetaTags
  openGraph={{
    type: 'website',
    url: 'https://www.example.com/page',
    title: 'Open Graph Title',
    description: 'Open Graph Description',
    images: [
      {
        url: 'https://www.example.ie/og-image.jpg',
        width: 800,
        height: 600,
        alt: 'Og Image Alt'
      },
      {
        url: 'https://www.example.ie/og-image-2.jpg',
        width: 800,
        height: 600,
        alt: 'Og Image Alt 2'
      }
    ]
  }}
/>
```

上記のように書くと`<head/>`タグ内に以下のようにレンダリングされます。

```html
<meta name="robots" content="index,follow">
<meta name="googlebot" content="index,follow">
<meta property="og:url" content="https://www.example.com/page"> 
<meta property="og:type" content="website">  
<meta property="og:title" content="Open Graph Title"> 
<meta property="og:description" content="Open Graph Description"> 
<meta property="og:image" content="https://www.example.ie/og-image.jpg"> 
<meta property="og:image:alt" content="Og Image Alt"> 
<meta property="og:image:width" content="800"> 
<meta property="og:image:height" content="600">
<meta property="og:image" content="https://www.example.ie/og-image-2.jpg"> 
<meta property="og:image:alt" content="Og Image Alt 2"> 
<meta property="og:image:width" content="800"> 
<meta property="og:image:height" content="600"> 
```

他にも`Video` `Article` `Book` `Profile`の形式をサポートしています。
詳しくは[こちら](https://github.com/oekazuma/svelte-meta-tags#open-graph)から確認してください。

## 構造化データを設定する

構造化データは`<MetaTags/>`コンポーネントとは別に`<JsonLd/>`コンポーネントを呼び出して使用しますのでその点注意してください。
`<JsonLd/>`コンポーネントは複数呼び出して使用することが可能です。


```js
<script>
  import { JsonLd } from 'svelte-meta-tags';
</script>

<JsonLd
  schema={{
    '@type': 'Article',
    mainEntityOfPage: {
      '@type': 'WebPage',
      '@id': 'https://example.com/article'
    },
    headline: 'Article headline',
    image: [
      'https://example.com/photos/1x1/photo.jpg',
      'https://example.com/photos/4x3/photo.jpg',
      'https://example.com/photos/16x9/photo.jpg'
    ],
    datePublished: '2015-02-05T08:00:00+08:00',
    dateModified: '2015-02-05T09:20:00+08:00',
    author: {
      '@type': 'Person',
      name: 'John Doe'
    },
    publisher: {
      '@type': 'Organization',
      name: 'Google',
      logo: {
        '@type': 'ImageObject',
        url: 'https://example.com/logo.jpg'
      }
    }
  }}
/>

```

上記のように書くと`<head/>`タグ内に以下のようにレンダリングされます。

```html	
<script type="application/ld+json"> 
{
  "@context": "https://schema.org",
  "@type": "Article",
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://example.com/article"
  },
  "headline": "Article headline",
  "image": ["https://example.com/photos/1x1/photo.jpg", "https://example.com/photos/4x3/photo.jpg", "https://example.com/photos/16x9/photo.jpg"],
  "datePublished": "2015-02-05T08:00:00+08:00",
  "dateModified": "2015-02-05T09:20:00+08:00",
  "author": {
    "@type": "Person",
    "name": "John Doe"
  },
  "publisher": {
    "@type": "Organization",
    "name": "Google",
    "logo": {
      "@type": "ImageObject",
      "url": "https://example.com/logo.jpg"
    }
  }
} 
</script>
```

[svelte-meta-tags](https://github.com/oekazuma/svelte-meta-tags)は[schema-dts](https://github.com/google/schema-dts)を使用しているのでほぼすべての形式をサポートしています。
詳しくは[こちら](https://github.com/oekazuma/svelte-meta-tags#json-ld)から確認してください。

## 型をimportして使用する

TypeScriptを使用している場合、型をimportして使用することができます。

ちなみにですが、**Svelte v3.39**以降と**svelte-preprocess v4.95**以降を使用している場合は型のimportを分離する必要がなくなり、1行でimportが書けるようになりました。

```js
<script lang="ts">
  import { MetaTags, JsonLd, MetaTagsProps, JsonLdProps } from 'svelte-meta-tags';

  const metatags: MetaTagsProps = {
    title: 'Types Page Title | Svelte Meta Tags',
    description: 'Description of Types page',
    canonical: 'https://www.canonical.ie/',
    openGraph: {
      type: 'website',
      url: 'https://www.example.com/page',
      locale: 'en_IE',
      title: 'Open Graph Title',
      description: 'Open Graph Description',
      images: [
        {
          url: 'https://www.example.ie/og-image.jpg',
          width: 800,
          height: 600,
          alt: 'Og Image Alt'
        }
      ],
      site_name: 'SiteName'
    },
    twitter: {
      handle: '@handle',
      site: '@site',
      cardType: 'summary_large_image'
    },
    facebook: {
      appId: '1234567890'
    }
  };

  const jsonld: JsonLdProps = {
    schema: {
      '@type': 'NewsArticle',
      mainEntityOfPage: {
        '@type': 'WebPage',
        '@id': 'https://google.com/article'
      },
      headline: 'Article headline',
      image: [
        'https://example.com/photos/1x1/photo.jpg',
        'https://example.com/photos/4x3/photo.jpg',
        'https://example.com/photos/16x9/photo.jpg'
      ],
      datePublished: '2015-02-05T08:00:00+08:00',
      dateModified: '2015-02-05T09:20:00+08:00',
      author: {
        '@type': 'Person',
        name: 'John Doe'
      },
      publisher: {
        '@type': 'Organization',
        name: 'Google',
        logo: {
          '@type': 'ImageObject',
          url: 'https://google.com/logo.jpg'
        }
      }
    }
  };
</script>

<MetaTags {...metatags} />

<JsonLd {...jsonld} />
```

# おわりに

今回は[svelte-meta-tags](https://github.com/oekazuma/svelte-meta-tags)というライブラリを用いて、SvelteプロジェクトでSEOに必要なメタデータを管理する方法を説明いたしました。

実は[svelte-meta-tags](https://github.com/oekazuma/svelte-meta-tags)というのは筆者が初めて自作したOSSライブラリです。
SvelteKitには[PACKAGING](https://kit.svelte.dev/docs#packaging)というコンポーネントライブラリを作成できる機能があるので今回はそれを使用し、勉強も兼ねて作成しました。
筆者がSvelteでWebサイトを構築する中で毎回それぞれのプロジェクトでメタデータを管理するコンポーネントを作成しないといけないのが面倒だったので、Next.jsで主に使われているライブラリの[next-seo](https://github.com/garmeeh/next-seo)のようなものがSvelteにもあればいいのになと思っていました。
調べてみると似たようなライブラリはいくつか見つかるのですが、どれも[next-seo](https://github.com/garmeeh/next-seo)と同等の機能は備えられていないものが多かったので自分で[next-seo](https://github.com/garmeeh/next-seo)をインスパイアしたライブラリを作ってみようと思って作成し、公開したところありがたいことにたくさんダウンロードしていただいたり、GitHubのスターをもらったり、Svelteの公式ブログで紹介していただけたりしました。

これからSvelteでWebサイトを構築しようとしている方にも使っていただいて改善していきたいと思っていますので宣伝も兼ねるかたちになってしまいましたが、ご参考、ご活用いただけると幸いです。

# リンク集
- [svelte-meta-tagsリポジトリ](https://github.com/oekazuma/svelte-meta-tags)
- [svelte-meta-tagsを使用したデモ](https://svelte.dev/repl/ffd783c9b8e54d97b6b7cac6eadace42?version=3.43.1)
- [svelte-meta-tagsが紹介されたSvelte公式ブログの記事](https://svelte.dev/blog/whats-new-in-svelte-september-2021)
- [Made with Svelte](https://madewithsvelte.com/svelte-meta-tags)