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

2020-05-19

(LastUpdated: 2020-05-19)

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

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

シンプルに、カテゴリと同じ方法を使えば、ごく簡単にできます。 しかし! せっかく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>タグとの競合

ソファに深くかけてリラックスした男性がmacを操るすがた 問題としては、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 }}" 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の高さ自動設定は、実装を諦めました。

試験版の自動高さ調整

一応、試験的に、高さの自動取得の機能が提供されています。 が、開発中の様です。 https://amp.dev/documentation/components/amp-list#dynamic-resizing

試してみたのですが、想定どおりの挙動にならず・・・😓

一応、実装方法を残しておきます。

html html <amp-list layout="container"></amp-list> Css css amp-list div[role=list]{ height: auto; } Cssでもheightの指定を入れてやらないと、高さがゼロになってしまうようです。

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

ノートパソコンの画面を見て「キーッ!」と鉛筆を噛む美しい女性 開発環境としてのnuxt.jsの恩恵は計り知れないのですが、AMPの実装は一筋縄ではいかない場面が多々ありますね。

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

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


タグに関連づけられた記事

AM2

JAMstacなブログにまつわる、技術的なことなどを記録しています。