AMPでタグごとの記事リストを「動的に」切り替える

各記事につけられたタグをタップすると、タグごとの記事リストを表示するページを作りたいと思いました。

このブログに実装済みです。
記事の下の方にあるカプセル状の青ボタンをタップすると、挙動を確認できます。

シンプルに、カテゴリと同じ方法を使えば、ごく簡単にできます。
しかし!
せっかくAMPで動いているんだから、amp-listを使って、動的なページっぽく動かしたい!

そんな気持ちでトライしてみました。
実際のところ、nuxt.jsの仕様とAMPの仕様、そのほか知らないことばかりで混迷を極めました。

なんとかして切り抜けた自分を褒めてあげたい。

それは置いといて、やることの流れを整理します。

まず、タグごとに記事一覧の jsonファイルを出力 します。
tag/index.htmlに、amp-listを実装します
遷移元から指定されたタグを取得 し、jsonをソースに、記事一覧を表示すると言う流れです。

  1. jsonファイルを生成する
  2. amp-list & amp-mustache
  3. QUERY_PARAM()を使って動的にjsonを読み込む
  4. 第一関門:vueの<template>タグとの競合
  5. 第二関門:amp-listの高さを動的に変化させる
  6. 教訓:苦しすぎるnuxt.jsとAMPの共存

jsonファイルを生成する


nuxt.jsでも使っている記事データを集約したjsonから、タグと一致する記事を抜き出し、amp-listで使えるjson形式に整形。
そして、それらをJsonファイルとして出力します。

amp-listで使うためのjson

amp-listで使えるJsonには、書き方のルールが定められています。
よって、以下の様な形式で作らねばなりません。

{
  “items”: [
    {
      “title”: “amp-carousel”,
      “url”: “https://ampbyexample.com/components/amp-carousel”
    },
    …
  ]
}

itemsのなかにオブジェクトを格納する必要があります。

amp-list & amp-mustache


amp-listは単体ではなく、amp-mustacheと一緒に使います。
amp-listでjsonファイルを配列に読み込み、amp-mustacheでレイアウトテンプレートと変数の配置を行います。

上記のjsonを読み込んだ例をは以下の通り。

<amp-list layout="fixed-height" height="100" src="/static/samples/json/examples.json" binding="no">
  <template type="amp-mustache">
    <div><a href="{{url}}">{{title}}</a></div>
  </template>
</amp-list>

こんな感じで簡単に展開してくれます。
AMPのこのスピード感は、素晴らしいと思います。

QUERY_PARAM()を使って動的にjsonを読み込む

![なんらかの細胞的なものを顕微鏡で見たオレンジ色の背景が映える画像]
さて次は、tagページへのリンクにパラメータを渡して、tag/index.html側でjsonファイル名を動的に指定して一覧を表示させたい。

リンクさせるURLにパラメータをつける

このブログの下部にある、タグに関連する記事紹介エリア。
ここにある「タグ名」にリンクを貼ります。

https://chaos-boy.tokyo/tag/?tag=mac

こんな感じで、tag/index.htmlにパラメータを渡します。

amp-listでQUERY_PARAMを受け取る

以下のようにすることで、amp-listでパラメータをsrcに反映できます。

<amp-list width="auto" height="500" load-more="manual" src="/json/QUERY_PARAM(tag).json">

これでタグで指定されたjsonファイルを、読み込むことができます。

amp-mustacheのtemplateタグ

jsonファイルから記事一覧を取得することができるようになります。
配列から変数を取り出すのに、amp-mustacheを使います。

<amp-list layout="fixed-height" height="100" src="/static/samples/json/examples.json" binding="no">
  <template type="amp-mustache">

ここで必要になる、<template>タグ。
これの扱いで一苦労することになります。

第一関門:vueの<template>タグとの競合


問題としては、vueで使用する<template>タグが、htmlのカスタムタグの<template>と重複する点です。
カスタムタグとして使いたいのに、vueの<template>タグとして処理されてしまう。

これにはかなり手を焼きました。

さらにpugを使ったので混乱。
コンパイル時にバリデーションがかかるからか、うまく展開されなくて、余計に問題が膨らんでしまいました。

また、v-htmlでも混乱。
以下の様なことをやろうとしていたんですが、これも出来ません。

<template v-html=“<template>”>
	<—! 間に挟みたかったコード —>
<template v-html=“</template>”>

冷静に見れば、おかしなことを書いているわけですけれど、藁をも掴むような思いでしたね。
自動でバリデーションされるため、このやり方では、間にコードを挟むことができません。

解決策:v-htmlにひたすら書く

解決するには、v-htmlの中に直に書いていくという、かなり無理矢理な方法しかありませんでした。

<template>タグって、結構使うようになる気がするんだけど、どうなんだろうかこの仕様は。

<amp-list width="auto" height="500" load-more="manual" src="/json/QUERY_PARAM(tag).json">
      <div v-html='`
        <template type="amp-mustache">
          <div class="flex mb4">
            <div class="col-3 mr2">
              <a href="{{ url }}" aria-label="{{ title }}の記事にリンクする">
                <amp-img class="block_shadow mb1" src="/img/blog/{{ img }}" alt="{{ title }}" width="375" height="375" layout="responsive"></amp-img>
              </a>
            </div>
            <div class="col-9 relative flex flex-wrap">
              <a class="col-12 text-decoration-none" href="{{ url }}">
                <div class="archiveListTitle">{{ title }}</div>
              </a>
              <div class="justify-end italic px1 emerald">
                <h6>{{ category }} | {{ date }}</h6>
              </div>
            </div>
          </div>
        </template>
      `'></div>
    </amp-list>

なんか無理やり感ありますが・・・
ひとまずamp-listを機能させることができました。

第二関門:amp-listの高さを動的に変化させる


せっかく動的にコンテンツを取得できたわけです。
ここまできたら、amp-listのブロックの高さを、自動でフィットさせて欲しいと思うのが、人情。

しかし、AMPの使用上それができないのです。
今は試験的に、高さの自動取得の機能が提供されていますが、開発中の様です。
安定版ではなさそうです。
ひとまず、amp-listの高さ自動設定は、実装を諦めました。

教訓:苦しすぎるnuxt.jsとAMPの共存


開発環境としてのnuxt.jsの恩恵は計り知れないのですが、AMPの実装は一筋縄ではいかない場面が多々ありますね。

AMPもフレームワークですし、静的なサイトと言う点でコンセプトも重なります。
jsonを扱えると言うことは、ヘッドレスCMSなどで手軽にブログも実装できます。

そう考えると、nuxt.jsをベースにAMPを開発すること自体がナンセンスなのかもしれませんね。

Social Share
ChaosBoy

テーマは「脱・思考停止」。
コメントはtwitterでお気軽に。