amp-listを使ってNext.jsの静的サイトに他のブログ記事への誘導をランダムでつける

TL;DR

ブログでよくある、関係のある記事をランダムで記事の一番下につけたかったのですが、静的サイトだとどうすればいいのかよくわかりませんでした。一つは毎回ServersideProps呼ぶ、ということだと思うんですが、それとgetStaticsPropsの併用、どうやるんだ?ってところでよくわからなくなりました。毎回サーバーサイドレンダリングしてると、遅くなりそうで嫌なので...

そこで、今回とったアプローチは、Next.jsでAPIをまず実装し、それをamp-listを使ってfetchしてその結果をレンダリングするというアプローチを取りました。

amp-listとamp-mustache

amp-listは、AMPの拡張コンポーネントでJSONエンドポイントから動的にデータを取得し、amp-mustacheのtemplateを使用してレンダリングを行うことができます。

公式ドキュメント(amp-list, amp-mustache)の例は以下の感じです。

<amp-list width="auto"
  height="100"
  layout="fixed-height"
  src="/static/inline-examples/data/amp-list-urls.json">
  <template type="amp-mustache">
    <div class="url-entry">
      <a href="{{url}}">{{title}}</a>
    </div>
</template>
</amp-list>

公式プレイグランド

使用しているJSONは以下

{
  "items": [
    {
      "title": "AMP YouTube Channel",
      "url": "https://www.youtube.com/channel/UCXPBsjgKKG2HqsKBhWA4uQw"
    },
    {
      "title": "AMP.dev",
      "url": "https://amp.dev/"
    },
    {
      "title": "AMP Validator",
      "url": "https://validator.amp.dev/"
    },
    {
      "title": "AMP Playground",
      "url": "https://playground.amp.dev/"
    }
  ]
}

基本的には、<amp-list>内でレイアウトとエンドポイントを指定し、<template type="amp-mustache">内でどういうふうにレンダリングするかを決めます。

amp-mustacheでは、以下のように変数を利用できます。

  1. ただの変数

{{変数名}}

<!-- Using template tag. -->
<template type="amp-mustache">
  Hello {{world}}!
</template>
  1. 変数が存在していればレンダリング

{{#section}}{{/section}}

<!-- Using template tag. -->
<template type="amp-mustache">
    {{#world}}
        Hello {{world}}!
    {{/#world}}
</template>
  1. 変数が存在していなければレンダリング

{{^section}}{{/section}}

<!-- Using template tag. -->
<template type="amp-mustache">
    {{^world}}
        No World!
    {{/#world}}
</template>

JSX内でのテンプレート

JSX内ではこれらのテンプレートは

<template type="amp-mustache">
  Hello {"{{world}}"}!
</template>;

のように利用できます。

実装方針

これらのことから、/api/otherarticlesのようなエンドポイントを作成し、そこから

[
  {
    "title": "test post",
    "url": "/posts/test"
  }
]

のようなものを返すことにします。

そうするとamp-listの実装は

<amp-list
  width="auto"
  height="200"
  layout="fixed-height"
  src={`/api/otherarticles`}
  items="."
>
  {/* @ts-ignore */}
  <template type="amp-mustache">
    title={"{{title}}"}
    url={"{{url}}"}
  </template>
</amp-list>;

のようにすればよいです。

APIの実装

Next.jsのAPIは、pages/api/下にtsなどのファイルを作ればエンドポイントが作成できます。

pages/api/otherarticles.js

export default function handler(req, res) {
    const articles = {
        title: "test post",
        url: "/posts/test"
    }

    res.status(200).json(articles) 
}

のような感じです。

実際の実装では、Next.jsで作ってみたブログに検索機能を導入するのような感じでキャッシュを作成しておいて、そのキャッシュを参照してランダムな配列から規定数のファイルを取り出しています。このブログのその部分の実装はgithubにあります。

この記事に関するIssueをGithubで作成する

Read Next