Open48
Hugo再入門
サイト設定
- サイト設定は
toml/yaml/json形式が使えるで、自分の好きなものを選ぶ - デフォルト値は
/config.toml -
hugo --config ファイル名で設定することができる
$ hugo --config staging.toml
テーマの設定の引き継ぎ
New in v0.84.0 となっている機能
- その直前の不便さを知らないので、現在は、デフォルトの挙動でよきようになっていると思って使うことにする
- なので、ここは必要になったら読むことにする
-
v0.109.0から設定ファイルはhugo.tomlになった - 現在は後方互換性のため
config.tomlでもOKだが、移行を推奨
設定ファイルのディレクトリ構造
- 設定ファイルは複数ファイルに分割できる
- 設定項目は下記のとおり
The root configuration keys are:
build, caches, cascade, deployment, frontmatter, imaging, languages, markup, mediatypes, menus, minify, module, outputformats, outputs, params, permalinks, privacy, related, security, server, services, sitemap, and taxonomies.
- 基本はHugoのデフォルトでよさそうだが、以下の設定ファイルは作ったほうがよい
/config/_default/
|-- hugo.toml
|-- languages.ja.toml
|-- menus.ja.toml
|-- params.toml
環境(=用途)ごとに設定を変更できる
- 環境(=用途)ごとにサブディレクトリを作成することで、設定を分岐できる
- デフォルト設定(
config/_default/)は必ず読み込まれるので、違うところを書いておけばOK - 例:ステージングとプロダクションで公開URLが異なる場合は、
baseURLだけ変更すればOK
環境を指定して構築
$ hugo --environment staging
$ hugo -e production
-
--environment / -eオプションで環境を指定して構築できる - デフォルトではの環境は以下のとおり
-
hugo server=development -
hugo=production
となっている
-
- 設定ファイルの構造化の具体例は、Blowfishのドキュメントがとても参考になった
- というか、これをそのまま真似た
言語ごとの設定項目
- 多言語サイト(日本語と英語)を想定した
- 共通の設定 :
hugo.toml - 日本語の設定 :
languages.ja.toml - 英語の設定 :
languages.en.toml
- 共通の設定 :
config/_default/hugo.toml
baseURL = "https://example.com"
title = "ウェブサイト名"
copyright = "著作者表示"
theme = ["テーマ名"]
defaultContentLanguage = "ja"
defaultContentLanguageInSubdir = false # true / false
hasCJKLanguage = true
config/_default/languages.ja.toml
# [languages.ja]に相当
disabled = false
languageCode = "ja"
languageDirection = "ltr"
languageName = "日本語"
weight = 1
title = "ウェブサイト名(日本語向け)"
[params]
dateFormat = "2006-01-02"
description = "ウェブサイトの説明"
config/_default/languages.en.toml
# [languages.en]に相当
disabled = false
languageCode = "en"
languageDirection = "ltr"
languageName = "English"
weight = 2
title = "ウェブサイト名(in English)"
[params]
dateFormat = "2006-01-02"
description = "ウェブサイトの説明 in english"
-
v0.112.0で設定できる内容に変更があった- NG :
languages.ja.dateFormat = "2006-01-02" - OK :
languages.ja.params.dateFormat = "2006-01-02"
- NG :
- 変数にアクセスする方法も変わった
- NG :
{{ site.Languages.Params.dateFormat }} - OK :
{{ site.Params.dateFormat }}
- NG :
図の変換
- リサイズ、フィット、フィル、フィルターの処理ができる
-
Resize= 幅と高さを指定。幅だけ、高さだけの場合は、アスペクト比を保存してリサイズ。 -
Fit= 幅と高さを指定。アスペクト比を保存してリサイズ。 -
Fill= 幅と高さを指定。リサイズ&クロップ。 -
Filter= 画像にフィルターを適用。
- Page Bundle された画像は対象になる(ページ・リソース)
-
/assetsに置いた画像は対象になる(グローバル・リソース) -
/staticに置いた画像は対象にならない
- ページリソースを取得する場合
-
index.md(or_index.md)があるディレクトリにある画像 - 例として
./sunset.jpgを取得した場合
-
{{ $image := .Resources.Get "sunset.jpg" }}
- グローバルリソースを取得する場合
- 例として
/assets/images/sunset.jpgを取得した場合
- 例として
{{ $image := resources.Get "images/sunset.jpg" }}
- 違い
.Resources.Getresources.Get
マッチする画像を検索
- リソースから画像を取得する場合、
.Getを使ってピンポイントでファイル名を指定するのではなく、.GetMatchでキーワードを(正規表現で)指定することがよくある
例として、Blowfishの部分テンプレートでやっていることを確認した
- L3:
{{- $images : = .Resources.ByType "image" -}}- 画像ファイルを一括で取得
- L4:
{{- $featured := $images.GetMatch "*feature*" -}}- 画像ファイルのリストを持った変数(
$images)から、ファイル名にfeatureが含まれるファイルを取得
- 画像ファイルのリストを持った変数(
- L5 :
{{- if not $featured}} ......-
$featureがなかった場合、cover、thumbnailのいずれかが含まれるファイルを取得
-
- L14: ``{{ with .Resize "1200"x }}
- ファイルがある場合、
1200xにリサイズしてimgタグで表示する
- ファイルがある場合、
- ファイルがなければ、表示しない(なにもしない)
画像のフィルター一覧
- 画像ファイルにさまざまなフィルタ処理をかけることができる
内部テンプレート/ショートコード
-
Hugoの内部で定義されてるテンプレート/ショートコードの本体 - ドキュメントには全部の引数が書かれていない気がするので、ここを読んだ方が分かりそう
OGPの設定
opengraph.html-
og:title=.Title -
og.description=.Description/.Summary/.Site.Params.description -
og:type=article/website -
og:url=.Permalink -
og:image=$.Params.images> Featured画像 > カバー画像 = サムネイル画像 >$.Site.Params.images
og:image
-
$.Params.images= フロントマターで設定; 最初の6枚を使用 - Featured画像 = Page bundle; ファイル名に
*feature*を含む画像;1枚 - カバー画像 = Page bundle; ファイル名に
*cover*を含む画像;1枚 - サムネイル画像 = Page bundle; ファイル名に
*thumbnail*を含む画像;1枚 -
$.Site.Params.images= サイト設定で設定; 1枚
ビルトインのOpenGraph設定
以前、詳しく調べてたみたいだけど、このURLも貼っておく
- サイト設定(
config.toml)と各ページのフロントマターの設定の組み合わせ -
seriesのタクソノミーを使うとsee alsoのページに使われるらしい
The series taxonomy is used to specify related “see also” pages by placing them in the same series.
YouTube動画の埋め込み
{{< youtube id="必須" >}}
-
Shortcodesのドキュメントとソース(youtube.html)を読むと
-
id: 必須 -
title: 文字列("YouTube Video") -
autoplay: ブーリアン(false) -
class: クラス名(デフォルトのiframeのスタイル)
-
-
[privacy.youtube.disable]の値で、Cookieの利用をどうするか変更できる-
disable = false(デフォルトの挙動)の場合は、外部プレイヤーに移動しても、Cookieを使ったトラッキングがON -
disable=trueの場合は、youtube-nocookieで埋め込まれ、埋めんだ動画を再生しないかぎり、ユーザー情報は残らない
-
プライバシー設定
- サイト設定でいろんなサービスのプライバシー設定(GDPR対策)ができる
PostCSS
-
PostCSS= CSSをビルドするためのフレームワーク- ベースとなるCSSから新しいCSSを作ることができる
- 例:
autoprefixerで ベンダー用 prefix を追加する、とか
-
npmを使ってある程度のパッケージのインストールが必要-
postcss/postcss-cli/autoprefixer
-
- 設定は
/postcss.config.jsに書く
{{ $css := resources.Get "css/main.css" }}
{{ $style := $css | resources.PostCSS }}
-
/assets/css/main.cssを読み込んでPostCSSに食べさせている - たぶん(じゃなくても)、このように一行で書くこともできる
- Goの書き方を間違えているかもしれないけど、やりたいことは分かるはず
{{ $style := resources.Get "css/main.css" | resources.PostCSS }}
-
PostCSSの使い方
- この使い方の例が、上と同じ
$ cat input.css | postcss -u autoprefixer > output.css # Piping input & output
-
cat input.css= 元のCSSを読み込む(パイプする) -
-u autoprefixer= プラグインを指定する(ここではautoprefixer) -
> output.css= 変換したCSSを書き出す - オプションは他にもあって、使うものは
postcss.config.jsに書いておくことができる
- ここに書いてあることを試してみた
-
postcss.config.jsをそのまま真似するとエラーが出る
ERROR 2022/03/11 05:36:54 POSTCSS: failed to transform "style.css" (text/css):
TypeError: Cannot read properties of undefined (reading 'config') at getTailwindConfig (node_modules/tailwindcss/lib/lib/setupTrackingContext.js:81:62)
- PostCSSのドキュメントにあるように
requireを使った書き方に修正するとエラーが出なくなった
postcss.config.js
module.exports = {
plugins: [
require('tailwindcss')({}),
require('autoprefixer')({}),
]
}
- でもページにCSSが適用されていない。どうして?
自分でイチからやってもできなかったけれど、tellaというテーマを使ってみたら、問題なくできた。これをベースにちょっとずつ理解していこう。
日時のフォーマット指定
time.Format 日付フォーマット 入力値
- 日付フォーマットは
"Mon Jan 2 15:04:05 2006 MST"を並び替えて指定する必要がある-
MSTは米国山岳標準時 = UTC-07
-
この値を使う理由はよく知らない・・・
-
0 1 2 3:4:5 6 7みたいな並びになってるのかな? - Hugoを使いはじめたとき、この日時に意味があることを知らなかったので、日付が全く表示されなくて困ったことがあった(いやぁ、分かんないよ)
predefinedなフォーマッタ
-
v0.87.0以降のHugoに predefined なフォーマッタが追加された
{{ .Date | time.Format ":date_full" }} // => Thursday, Mar 17, 2022
{{ .Date | time.Format ":time_full" }} // => 11:41 pm UTC
- あまり(僕の好み的に)使えそうなフォーマッタはない
- 日本語の場合どういう表示になるか確認が必要
現在時刻
- フッタにコピーライト表示する場合に使えるテンプレート
{{ now.Format "2006" }}
ビルトインな日時のフォーマット
- Hugoにビルトインされてる日時の変数には
.Formatが使える - ビルトイン日時
.Date/.PublishDate/.Lastmod
{{ .Date.Format "2006-01-02" }}
メニューの追加
- サイトのメニュー(ナビゲーション)の作成に使うことができる機能
- 簡単に多言語対応できる
config/_default/menus.ja.toml
[[main]]
name = "About"
pageRef = "about"
weight = 10
[[main]]
name = "ブログ"
pageRef = "posts"
weight = 20
config/_default/menus.en.toml
[[main]]
name = "About"
pageRef = "about"
weight = 10
[[main]]
name = "Posts"
pageRef = "posts"
weight = 20
セクション
-
/content/直下の first-level のディレクトリ名がsectionになる -
_index.mdがあるサブディレクトリもsectionになる
- セクションテンプレートが自動で適用されるのは
1の場合 -
2の場合はフロントマターでtypeorlayoutを設定する必要がある
Index Pages: _index.md
-
_index.mdに frontmatter と content を書くことができる - これらは list templates (
section/taxonomy/terms/homepage)で読み込むことができる
Section Templates
5つの kind それぞれのインデックスページがある。
日本語にしても分かりにくいだけなので、URLを見て理解するほうがよいと思う
-
home= トップ(/index.hdml) -
page= 記事/ページ(/posts/my-post/index.html) -
section= セクション(/posts/index.html) -
taxonomy= タグ自体のインデックス(/tags/index.html) -
term= タグの中の単語のインデックス(/tags/name/index.html)
Create kind-specific lists of content
{{ .Site.GetPage "ページの種類" "値" }}
-
postsセクションの一覧が欲しい
{{ .Site.GetPage "section" "posts" ]]
-
searchページの一覧が欲しい
{{ .Site.GetPage "page" "search" }}
Goldmark
- Markdownのレンダラーには
Goldmarkが使われている-
v0.60以降のデフォルト - それ以前は
BlackFridayが使われていた
-
- デフォルトでは
.mdファイルの中でHTMLタグなどを使うことができない - HTMLタグを使いたい場合は
unsafe = trueに変更しないといけない- FontAwesomeなどアイコンフォントを使う場合は、設定を変える必要があるかもしれない
config.toml
[markup]
[markup.goldmark.renderer]
unsafe = true
Google Analytics の設定
-
UA-タグが2023年7月に廃止になるみたい - Hugoの中で
UA-タグからG-タグへの変更がどうなってるのか確認した - 該当のファイルを見つけるために、トラッキングコードに使われている
googletagを含むファイルを検索した
$ rg googletag
docs/_vendor/github.com/gohugoio/gohugoioTheme/layouts/partials/gtag.html
2:<script async src="https://www.googletagmanager.com/gtag/js?id={{ . }}"></script>
tpl/tplimpl/embedded/templates/google_analytics.html
4:<script async src="https://www.googletagmanager.com/gtag/js?id={{ . }}"></script>
tpl/.../google_analytics.htmlの中身を確認
- プライバシー設定(
.Site.Config.Privacy.GoogleAnalytics)の値を確認 - GoogleアナリティクスのID(
.Site.GoogleAnalytics)の値を確認 -
{{ if hasPrefix . "G-" }}/{{ else if hasPrefix . "UA-" }}となっていて、どちらにも対応
UA-とG-は併用できなさそうなので、さっさとUAをGに切り替えるのがよさそう
UAからGA4に移行する手順
- GA4では
gtags.jsの利用が必須になっている -
gtags.jsを使っている場合は「既存のタグを使用してデータ収集を有効にする」を使えばOK
サイトマップの設定
-
config.tomlの[sitemap]でグローバルに設定できる-
disableKindsに入れると生成しないようにできる
-
- ページのフロントマターで個別に設定できる
- カスタマイズしたい場合は
layouts/sitemap.xml/layouts/_default/sitemap.xmlに作成する
config.toml
[sitemap]
changefreq = "daily"
priority = 0.5
-
filenameはデフォルトのまま(sitemap.xml)でいいので書いていない -
changefreqはalways/hourly/daily/weekly/monthly/yearly/neverから選択する -
priorityは0.0から1.0の間で指定する
公開URL
- サイト設定(
config.toml)で指定したcontentDirのフォルダ/ファイル階層に従って、publishDirにHTMLファイルが生成される -
permalinks設定で、公開URLのルールを変更することができる
設定例
config.toml
[permalinks]
posts = "/posts/:year/:month/:day/:03:04/"
pages = "/:section/:filename/"
- 記事ページ(
posts)と固定ページ(pages)で、公開URLのルールを変更する- すべての投稿コンテンツは「公開日に意味がある or ない」で区別して、いずれかに分類する
- 記事ページは公開日をベースに
/posts/年/月/日/時分/にする- Go time format が使えるらしいので時(
:03)分(:04)で設定できるはず
- Go time format が使えるらしいので時(
- 固定ページはファイル名をベースに
/セクション/ファイル名/にする
Pretty URLs と Ugly URLs
- Hugoのデフォルトは
pretty URL -
pretty URLはURL末尾がファイル名/となる(要するにindex.htmlが作成される) -
ugly URLはURL末尾がファイル名.htmlとなる - 好みの問題かもしれない
canonifyURLsとrelativeURLs
- コンテンツ内の基本的にそのまま処理される
- すべてを絶対パスに変換したい場合は
config.tomlで設定できる- SEO対策のcanonical化とは関係がなさそう
config.toml
canonifyURLs = true # デフォルトは false
- 相対パスに変換する設定もある
- すでに絶対パスで入力されているものは変換されない
config.toml
relativeURLs = true # デフォルトは false
タクソノミー
- 日本語訳を調べると「分類」「分類法」「分類学」とか出てくるけど、ちょうどいい日本語ってなんだろう?
-
categoriesやtagsの機能のこと
デフォルトで有効になっている設定
[taxonomies]
category = 'categories'
tag = 'tags'
-
単数形="複数形"の形で書くのが基本(とどこかに書いてあったきがする) - それぞれの値は記事のフロントマターで設定する
+++
title = "記事のタイトル"
categories = ["カテゴリ1", "カテゴリ2"]
tags = ["タグ1", "タグ2", "タグ3"]
+++
日本語のカテゴリ名/タグ名
- カテゴリ/タグの値はそのままURLになる
- カテゴリ名/タグ名が日本語の場合、URLが日本語になる
日本語が混じったURL
https://example.com/categories/カテゴリ1/
https://example.com/categories/カテゴリ2/
https://example.com/tags/タグ1/
https://example.com/tags/タグ2/
https://example.com/tags/タグ3/
英語スラッグにしたい
- 日本語URLでもアクセスするには問題ない
- でも、URLを共有するときを考えると、URLは英語にしておきたい
URLは英語にしておきたい
https://example.com/categories/category1/
https://example.com/categories/category2/
https://example.com/tags/tag1/
https://example.com/tags/tag2/
https://example.com/tags/tag3/
ちょっと調べてみているがconfig.tomlでできることはなさそう🤔
代替手段(たぶん;まだテストしてない)
- フロントマターにはカテゴリ名/タグ名を英語で入力する
記事のフロントマター
+++
title = "記事のタイトル"
categories = ["category1", "category2"]
tags = ["tag1", "tag2", "tag3"]
+++
- それぞれのカテゴリ名/タグ名に対して
_index.mdを作成する
_index.mdのパス
/content/categories/category1/_index.md
/content/categories/category2/_index.md
/content/tags/tag1/_index.md
/content/tags/tag2/_index.md
/content/tags/tag3/_index.md
-
_index.mdのフロントマターに日本語タイトルを書く
_index.mdのフロントマター
+++
title = "カテゴリ1"
+++
たぶんこれでいけるはず😎
Taxonomy Templates
taxonomy list pagestaxonomy terms pagessingle page
Taxonomy List Templates
-
list pagesのテンプレートの変数/メソッドが使える
多言語サイト
-
.IsTranslated: 他の言語が存在するか -
.Translations: 他の言語の記事リスト
Page Variables
.Is系の変数を調べてみる
-
.IsHome:truein the context of the homepage -
.IsNode: alwaysfalsefor regular content pages..IsPageと対になるフラグ -
.IsPage: alwaystruefor regular content pages..IsNodeと対になるフラグ -
.IsSection:trueif.Kindissection -
.IsTranslated:trueif there are translation to display.
.Site.IsMultilingual.Site.IsServer.IsNamedParams
繰り返し
- ページの一覧を作ったり、フロントマターで設定した配列から値を取り出したりするときは
rangeを使う - とりあえずテンプレートに書いてみて、値を取り出せることを確認しながら、必要なコンポーネントを埋め込んでいけばよい
フロントマター
videos = ["attic/video0.mp4", "attic/video1.mp4", "attic/video2.mp4"]
ページ変数が配列であることを確認
{{ .Params.videos }}
// ==> [attic/video0.mp4 attic/video1.mp4 attic/video2.mp4]
配列から順番に読み出す
{{ range .Params.videos }}
{{ . }}
{{ end }}
// ==>
// attic/video0.mp4
// attic/video1.mp4
// attic/video2.mp4
変数名をつけて読み出すこともできる
{{ range $video := .Params.videos }}
{{ $video }}
{{ end }}
// ==> 結果は上と同じ
インデックスも読み出したい場合
{{ range $index, $video := .Params.videos }}
{{ $index}} : {{ $video }}
{{ end }}
// ==>
// 0 : attic/video0.mp4
// 1 : attic/video1.mp4
// 2 : attic/video2.mp4
最初の項目だけ条件をつける
- 画像/動画をスライダーを使って表示するときに、最初の項目に
class="active"をつける必要があった - 配列のインデックスが 0(``{{ if eq $index 0}}...{{ end }} )かどうかで判断することにした
説明に必要そうなHTMLタグに絞ってある
<div class="carousel-inner">
{{ range $index, $video := .Params.videos }}
<div class="carousel-item {{ if eq $index 0 }}active{{ end }}">
<video>
<source src="{{ $video | relURL }} " type="video/mp4">
</video>
</div>
{{ end }
</div>
テンプレートで変数を使いたい
{{ $var1 := "変数を代入" }}
- Goの基本的な書き方(なのかもしれない)
-
:=を使って変数を定義できる