AMP対応テンプレートを作成する

こんにちはnasustです。

今回は、ブログをAMP(Accelerated Mobile Pages)に対応するテンプレートを作成します。 HugoにはAMPに簡単に対応できる機能があります。single.htmlをAMPに対応します。 _defaultディレクトリに、baseof.amp.html、single.amp.htmlを作成します。

see also: Custom Output Formats | Hugo,Google 検索での AMP に関するガイドライン - Search Console ヘルプ

baseof.amp.html

<!DOCTYPE html>
<html  lang="ja">
    <head>
        {{ .Scratch.Set "output-format" "amp" }}

        <meta charset="utf-8" />
        <script async src="https://cdn.ampproject.org/v0.js"></script>
        <title>{{ .Title}}{{ if ne .Title .Site.Title }} | {{ .Site.Title }}{{ end }}</title>
        {{ with .OutputFormats.Get "html" }}
            <link rel="canonical" href="{{ .Permalink }}" />
        {{ end }}
        <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />

        {{ $eyecache_data := partial "function/get_eyecache_image" . }}
        {{ .Scratch.Set "eyecache_data" $eyecache_data }}

        <script type="application/ld+json">
            {
                "@context": "http://schema.org",
                "@type": "NewsArticle",
                "mainEntityOfPage": {
                    "@type": "WebPage",
                    "@id": "{{ with .OutputFormats.Get "html" }}{{ .Permalink | safeJS }}{{ end }}"
                },
                "headline": {{ .Title }},
                {{ if $eyecache_data.eyecache }}
                "image": [{{ $eyecache_data.eyecache.Permalink }}],
                {{ end }}
                "datePublished": {{ .PublishDate.Format "2006-01-02T15:04:05" }}},
                "author": {
                    "@type": "Person",
                    "name": {{ with .Site.Params.author }}{{ .  }}{{ end }}
                },
                "publisher": {
                    "name": "{{ .Site.Title  }}",
                    "logo": {
                      "@type": "ImageObject",
                      "url": ""
                    }
                }
            }
        </script>
        <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
        {{ $style := resources.Get "scss/style.scss" | toCSS | minify }}
        {{ $css_content := $style.Content }}
        {{ $css_content = replace $css_content `@charset "UTF-8"` "" }}
        <style amp-custom>{{ $css_content | safeCSS }}</style>
        <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css">
    </head>
    <body>
        <header class="m-global-header">
            <div class="m-logo">
                <a class="m-logo__link" href="/" >{{ .Site.Title }}</a>
            </div>
        </header>
        <main class="m-main">
            <div class="m-main-container">
                <div class="m-content-container">
                    {{ block "content" . }}
                        {{ .Content }}
                    {{ end }}
                </div>
            </div>
        </main>
        <footer class="m-global-footer">
            {{ partial "footer" . }}
        </footer>
    </body>
</html>
html

通常のHugoのテンプレートと同じようにAMPのHTMLを書いていきます。

.Permalinkは、AMPページのリンクになってしまいます。 htmlページのリンクにする為には、.OutputFormats.Get "html"でhtmlフォーマットを取得します。

see also: Custom Output Formats | Hugo

$style.Content

AMPではcssを直接HTMLに記述しなければなりません。 .Contentでcssの中身を展開します。

see also: Page Resources | Hugo

safeCSS

see also: safeCSSはテンプレートエンジンに文字列がCSSであることを宣言しています。

safeCSS | Hugo

partial “function/get_eyecache_image”

AMPに対応する為、アイキャッチ画像取得のテンプレートで画像の幅と高さを取得するようにしました。

AMPではimgタグが利用できません。代わりにamp-imgタグが利用できます。 amp-imgはwidthとheightの指定が必須です。

{{ $eyecache_image := 0 }}
{{ $width := 0 }}
{{ $height := 0 }}

{{ if or (isset .Params "eyecatch") (isset .Params "featured_image") }}
    {{ $eyecache_param := "" }}
    {{ with .Params.eyecatch }}{{ $eyecache_param = . }}{{ end }}
    {{ with .Params.featured_image }}{{ $eyecache_param = . }}{{ end }}

    {{ with .Resources.ByType "image" }}
        {{ range . }}
            {{ if eq (path.Base .Name) ( path.Base $eyecache_param) }}
                {{ $eyecache_image = . }}         
            {{ end }}
        {{ end }}
    {{ end }}
    {{ if $eyecache_image  }}
        {{ $width = $eyecache_image.Width }}
        {{ $height = $eyecache_image.Height }}
    {{ else }}
        {{ $path := printf "/assets/%s" $eyecache_param }}
        {{ if fileExists $path }}
            {{ $eyecache_image = resources.Get $eyecache_param | fingerprint }}
            {{ $imageConfig := imageConfig $path }}
            {{ $width = $imageConfig.Width }}
            {{ $height = $imageConfig.Height }}
        {{ end }}
    {{ end }}
{{ else if or (isset .Site.Params "eyecatch") (isset .Site.Params "featured_image")  }}
    {{ $eyecache_param := "" }}
    {{ with .Site.Params.eyecatch }}{{ $eyecache_param = . }}{{ end }}
    {{ with .Site.Params.featured_image }}{{ $eyecache_param = . }}{{ end }}

    {{ $path := printf "/assets/%s" $eyecache_param }}
    {{ if fileExists $path }}
        {{ $eyecache_image = resources.Get $eyecache_param | fingerprint  }}
        {{ $imageConfig := imageConfig $path }}
        {{ $width = $imageConfig.Width }}
        {{ $height = $imageConfig.Height }}
    {{ end }}
{{ end }}
{{ return dict "eyecache" $eyecache_image "width" $width "height" $height }}
html

imageConfig

指定したパスの画像の情報を取得します。 .Resources.GetMatchやresources.Getと違い画像をサイトのフルパスで指定しなければなりません。 その為、printf "/assets/%s" .Site.Params.eyecacheで画像パスを生成しています。

see also: imageConfig | Hugo

single.amp.html

single.htmlのAMP版です。特に新しい関数は無いですね。 single.htmlのCSSと共用で使用できるように、構造とCSSのクラス名は同じにしています。

{{ define "content" }}
    <article class="m-entry" >
        <div class="m-entry__header">
            <div class="m-entry__header-category">
                <span class="m-entry__header-category-title">
                    {{ .CurrentSection.Title }}
                </span>
            </div>
            <div class="m-entry__header-title">
                <a class="m-entry__header-title-link" href="{{ .Permalink }}" >
                    <h1 class="m-entry__header-title-link-text">{{ .Title }}</h1>
                </a>
            </div>
            <div class="m-entry__header-date">
                <time>{{ .PublishDate.Format "2006/01/02" }}</time>
            </div>

            {{ $eyecache_data := .Scratch.Get "eyecache_data" }}
            {{ if $eyecache_data.eyecache }}
                <div class="m-entry__header-eyecache">
                    <amp-img src="{{ $eyecache_data.eyecache.Permalink }}" width="{{ $eyecache_data.width }}" height="{{ $eyecache_data.height }}" layout="responsive" />
                </div>
            {{ end }}
        </div>
        <div class="m-entry__content">
            {{ .Content }}
        </div>
    </article>
{{ end }}
html

.Scratch.Get "eyecache_data"で別のテンプレートを超えてアイキャッチ画像を取得しています。 .Scratchはページのスコープの変数なので、同じページであればテンプレートファイルが別でも値を取得できます。

config.tomlでAMP出力の設定

[outputs]
    page = [ "HTML" , "AMP"  ]
toml

config.tomlでAMPの設定を追加します。 上記のように設定することで、/amp/post/entry/というようなURLにAMPのHTMLが出力されます。

see also: Custom Output Formats | Hugo

headタグにAMPのURLを追加します。

single.htmlがAMPに対応している事をGoogleが読み取れるように、 headタグにAMPページのURLを記述します。

{{ range .AlternativeOutputFormats -}}
    <link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
{{ end -}}
html

/post/entryの記事であれば下記のように出力されます。

<link rel="amphtml" type="text/html" href="https://xxxx/amp/post/entry">
html

see also: Custom Output Formats | Hugo

prevnext