Menu Close
  1. SIS Lab
  2. >
  3. Blog
  4. >
  5. HugoでAMP対応のブログカードを作る

HugoでAMP対応のブログカードを作る

更新日:2020.03.31 作成日:2020.02.02

「Hugoでもブログカードを利用したい」

そう考えているところに以下の記事がTwitterのTLで流れてきたので、試してみました。

Hugoでブログカードに対応する | Hugo 入門 / 解説 | nasust dev blog

ブログカードのShortcodeと表示例

{{% blogcard https://nasust.com/hugo/shortcode/blogcard/ %}}

Hugoでブログカードに対応する | Hugo 入門 / 解説 | nasust dev blog こんにちはnasustです。 今回は、Hugoでブログカードに対応する方法を紹介します。 私のもう1つのブログは、はてなブログを使用しています。...

blogcardというShortcodeを利用することで、対象ページのTitle, Description, OGPを取得して表示します。

Shortcodeblogcardの実装は以下の通りです。ローカルに立ち上げたAPIサーバ(Express)に対してgetJSONを行うことで、ビルド時に情報を取得します。

Shortcode for blogcard

{{ $url := ( .Get 0) }}
{{ $getURL := printf "http://localhost:6060/getogp?%s" (querify "url" $url ) }}
{{ $ogpjson := getJSON $getURL }}
{{ $getSizeURL := printf "http://localhost:6060/size?%s" (querify "url" $ogpjson.image ) }}
{{ $imgjson := getJSON $getSizeURL }}

<p></p><!-- Avoid overriding list -->
<div class="embed">
    <div class="rf">
        <div class="rr">
            <div class="rcx9 rcm9 rpls">
                <div class="rf">
                    <div class="rr">
                        <div class="rcx12 body">
                            <a class="utdn"
                                href="{{ $ogpjson.url }}"><strong>{{ $ogpjson.title }}</strong></a>
                        </div>
                        <div class="rcm12" style="font-size: .8rem;">
                            {{ $ogpjson.description | truncate 50 }}</small>
                        </div>
                    </div>
                </div>
            </div>
            <div class="rcx3 rcm3 rtxc rpxs rpls">
                <a href="{{ $ogpjson.url }}">
                    <div>
                        <amp-img class="" src="{{ $ogpjson.image }}"
                            alt="{{ $ogpjson.title }}" width="75" height="75" layout="fixed"></amp-img>
                    </div>
                </a>
            </div>
        </div>
    </div>
</div>

APIサーバ (app.ts)

上記記事を参考にさせていただきました。/sizeはサイズ取得が必要となったとき用にAPIを生やしました。

Hugoでブログカードに対応する | Hugo 入門 / 解説 | nasust dev blog

import * as express from 'express';
import * as client from 'cheerio-httpcli';
import * as requestImageSize from 'request-image-size';

const app = express();

app.get("/size", (expressRequest, expressResponse, expressNext) => {
    const url = expressRequest.query.url;
    client.fetch(url, (err, $, res, body) => {
        if (err) {
            expressNext(err)
            return;
        }

        requestImageSize(url)
            .then(size => {
                const result = {
                    width: size.width,
                    height: size.height,
                };
                expressResponse.json(result);
            })
            .catch(err => console.error(err));
    });
})

app.get("/getogp", (expressRequest, expressResponse, expressNext) => {
    const url = expressRequest.query.url;
    client.fetch(url, (err, $, res, body) => {
        if (err) {
            expressNext(err)
            return;
        }

        const result = {
            exists: false,
            title: "",
            description: "",
            url: "",
            image: "",
            site_name: "",
            type: "",
        }

        const ogTitleQuery = $("meta[property='og:title']");

        if (ogTitleQuery.length > 0) {
            result.exists = true;
            result.title = $("meta[property='og:title']").attr("content");
            result.description = $("meta[property='og:description']").attr("content");
            result.url = $("meta[property='og:url']").attr("content");
            result.image = $("meta[property='og:image']").attr("content");
            result.site_name = $("meta[property='og:site_name']").attr("content");
            result.type = $("meta[property='og:type']").attr("content");
        } else {
            result.title = $("head title").text()
            result.description = $("meta[name='description']").attr("content");
        }

        expressResponse.json(result);
    });

})

app.listen(6060, () => console.log('Listening on port 6060'));

CI(Azure Pipelines)での設定

CI上でも実行できるように事前にJSON API Serverを実行するようにしました。

- script: |
    npx ts-node src/app.ts &
  displayName: 'Run json api server'

- script: |
    hugo
  displayName: 'Build content by hugo'

まとめ

今まで、HugoのgetJSONを使うときには、外部にAPIサーバを立てないといけないという固定観念がありました。しかし、よく考えればローカルAPIサーバでも問題なく動作するので、使い方に幅が出そうです。

ただし、「動的にコンテンツを生成するのはHugoの哲学に沿っているのか」という点は少し検討すべきです。ビルドが超高速なため、編集・確認までをシームレスに行えるのがHugoの魅力です。getJSONを利用することでビルド速度が落ちてしまったら、魅力が半減してしまうことを懸念しています。(getJSONはキャッシュを行うので一度情報取得してしまえば問題ない可能性もあります)

しばらくは、試しながら様子を見てみます。

スポンサーリンク

Related contents

TECH

2019.10.11

AMPページの最適化〜ぼくのAMPサイトがこんなに遅い訳がない〜

TECH

2019.10.06

AMP向けのミニマルCSSフレームワーク「1BX」をHugoに導入した

TECH

2020.03.13

npm-run-allでローカルAPI serverとHugo serverを同時に実行する

TECH

2019.12.03

Homebrewで過去バージョンのパッケージをインストールする方法

TECH

2018.12.02

AMPページがモバイル表示で引っ掛かる件

TECH

2018.07.11

Hugoのテーマでsubmoduleを使う方法

TECH

2017.12.22

はてなダイアリーからはてなブログ経由で独自ドメインのブログに記事を移行しました

TECH

2017.11.19

SendGridのInbound Parseでメール受信をトリガーに処理を実行する