pop-web

スマートかつクールでアトラクティブなブログです

Hugoの自作テーマを作ろう![外伝]

概要

本記事は、マークダウンの静的htmlジェネレーターであるHugoとVuetifyというVueのフロントエンドを合体させてテーマを作れないか試行錯誤した失敗エピソードをまとめたものです。

無かったことにしてしまおうかとも思いましたが、とりあえずこれはこれで勉強になるので、一旦ここでまとめて出すことにします。

導入

とりあえず最初はここら辺を参考にします。

gohugo.io github.com www.neujournal.net

環境構築

Install Hugo

私はMacなのでbrewで一発です。

brew install hugo

とりあえず、ベーシックなテンプレをインストールしましょう。

git clone https://github.com/gohugoio/hugoBasicExample.git

これがあると自作のテーマが動くかテストできるようです。

Create

自作のテーマを作りましょう。 クローンしたリポジトリに移って、早速テーマを作成します。

cd hugoBasicExample
hugo new theme [Your theme name]

とのことなので私は

hugo new theme UltraPop

でいきます。themes/以下にフォルダが作成されているのを確認できると思います。

こんな感じのフォルダ構成。

.
├── LICENSE
├── README.md
├── config.toml
├── configTaxo.toml
├── content
│   ├── _index.md
│   ├── about.md
│   ├── archives.md
│   ├── homepage
│   │   ├── about.md
│   │   ├── index.md
│   │   └── work.md
│   └── post
│       ├── _index.md
│       ├── emoji-support.md
│       ├── markdown-syntax.md
│       ├── math-typesetting.md
│       ├── placeholder-text.md
│       └── rich-content.md
├── layouts
├── resources
│   └── _gen
│       ├── assets
│       └── images
├── static
└── themes
    └── UltraPop
        ├── LICENSE
        ├── archetypes
        │   └── default.md
        ├── layouts
        │   ├── 404.html
        │   ├── _default
        │   │   ├── baseof.html
        │   │   ├── list.html
        │   │   └── single.html
        │   ├── index.html
        │   └── partials
        │       ├── footer.html
        │       ├── head.html
        │       └── header.html
        ├── static
        │   ├── css
        │   └── js
        └── theme.toml

theme.tomlを弄りましょう。

GitHub - gohugoio/hugoThemes: A curated directory of Hugo themes

こいつを参考に弄ります。

# theme.toml template for a Hugo theme
# See https://github.com/gohugoio/hugoThemes#themetoml for an example

name = "UltraPop"
license = "MIT"
licenselink = "https://github.com/pop-ketle/Hugo-Theme/blob/main/themes/UltraPop/LICENSE"
description = "pop-ketle's theme for portfolio"
homepage = "http://example.com/"
tags = ["Blog", 'Portfolio', 'Docs', 'Gallery']
features = []
min_version = "0.41.0"

[author]
  name = "pop-ketle"
  homepage = ""

# If porting an existing theme
[original]
  name = ""
  homepage = ""
  repo = ""

とりあえずこんなもんかな。

nameはデフォで入ってると思うので、licenselinkとdescriptionとauthor書けばとりあえず十分だと思う。知らんけど。

多分公開する時にタグで検索しやすくなると思うので、Complete List | Hugo Themesの右端にあるタグからそれっぽいのを適当に選んだ。featureは良くわからん。homepageはまだないのでとりあえずノータッチで。

ここらで、とりあえず動かしてみよう。

$ hugo server

# こっちじゃないとダメかも
$ hugo server -t UltraPop

ローカルサーバが立ったと思います。私はhttp://localhost:1313/でした。クリックして見ましょう。人類が月面に降り立つ最初の一歩です。

f:id:pop-ketle:20211114071344p:plain

......見事に真っ白ですね.........

まぁ、当然何も書いていないのでそれはそうなります。コンテンツを作っていきましょう。

とりあえずindex.htmlにハローワールドの儀式をしましょうか。 ということで

hello world

f:id:pop-ketle:20211114073346p:plain

...やったぜ!(ここまでテンプレ)

ちなみにHugoはファイルを保存するたびに、rerun(という呼び方で良いのか知らないけど)するので、変更が自動で反映されるので便利です。

...さーてここからどうするかな......

実を言うとGo langにもフロントエンドにも別に詳しいわけじゃないのでここからどうしたら良いか、全く謎である。

Vuetify

Vuetify使ってみたいんだよなぁ...そう思っていたので張り切ってVuetifyを試して見ることにする。人生は冒険や!

f:id:pop-ketle:20211114081525p:plain なんだこいつ...トップページですら格好良すぎる...ということで「はじめよう」してみる。

まず.js系のパッケージを管理するのにnode.js入れる必要があるぽい。

Macなので...

brew install nodebrew
mkdir -p ~/.nodebrew/src
nodebrew install-binary latest
nodebrew use v17.1.0

とりあえず新しいのを入れてアクティブにした。JavaScriptなんかめんどくさいなやっぱり。

zsh使ってるので.zshrcに書き込んでパスを通す。ターミナル再起動してnodeコマンドが使えるようになったことも確認。

export PATH=$HOME/.nodebrew/current/bin:$PATH
$ node -v
v17.1.0

$ npm -v
8.1.2

とりあえずよし!

外伝のさらに外伝

これはVuetifyインストール失敗ルートです。

初見ではここでいきなりパッケージを入れ始めたのだが、まず

$ cd themes/UltraPop
$ npm init

する必要があるらしいということでやり直した。 package.jsonが作成される。

次はVueを入れて、ついにVuetifyを入れる!はずなのだがNuxt経由とWebpack経由の二つがあるらしい。 違いが全く分からない。Vuetifyを使いたいだけなのに、NuxtかWebpackを入れる必要があって、これを入れるためにVueを、vueを入れるために、node.jsを、node.jsを入れるためにnodebrewを入れてとしないといけない。JavaScriptは本当にごちゃごちゃしていて嫌いだ。

まぁ、pip installとかも裏でよしなに依存関係うまいことやってくれてるんだろうけど。

とりあえず、Nuxtは聞いたことあるし、見た感じWebpackも包含しているみたいなのでNuxtを入れてみる。

$ npm install vue
$ npm install @nuxtjs/vuetify -D

$ npm list                            
ultrapop@1.0.0 /Users/home/Desktop/work/Python/mywork/hugoBasicExample/themes/UltraPop
├── @nuxtjs/vuetify@1.12.1
└── vue@2.6.14

私のディレクトリ構成のおかげでPythonとか書いてあるけど気にしない。多分これでいいんだろう。

Vuetifyの公式サイトには

インストールしたら、nuxt.config.jsファイルを更新して、ビルドにVuetifyモジュールを含めます。

と書いてあるがnuxt.config.jsは見当たらない。





...いやこれnuxtいるか?

ということでまたやり直す。

本ルート

nuxt.config.jsが見つからなかったので、vue CLI経由で行うことにする。 多分static/js/ 配下に自分でファイル作って入れとけばうまくいきそうだけど、良く分からんしな。

$ npm init
$ npm install vue

# vue CLIを入れる
$ npm install -g @vue/cli

$  vue create vue_app
$ cd vue_app
$ vue add vuetify

$ npm list
ultrapop@1.0.0 /Users/home/Desktop/work/Python/mywork/hugoBasicExample/themes/UltraPop
├── @nuxtjs/vuetify@1.12.1
└── vue@2.6.14

あれ?nuxtくん勝手にはいってるんだけど...(めんどくさいので見なかったことにする。)

多分これでいいんだろう。途中途中、選択肢がいくつか出てきたけどそれっぽいのを選んでおいた。 もう少ししたらVuetify v3が出るみたいだし、そしたらここら辺の記述は陳腐化するだろうからいらないと思うので省く。

ついでに、作法らしいので.gitignoreにnode_modules/を追加しておく。

つーか、たかだかパッケージのインストールだけなのにやり方多すぎだろ。これだからJavaScriptってやつは...(以下略)

ちょっとだけHugoのテーマ開発

Vuetifyのインストールも終わったので、またサーバを立ち上げる。

$ hugo server -t UltraPop

さーてここからどうすればいいんだろうな?(フロントエンド ヌーブ並感)

とりあえずheaderを作るか。

このサイトや、他の人の既存テーマを参考に適当に書いてみる。 it-omurice.tokyo

blog.blackcoffy.net

悲しいことに、はてなでコードを書くと改行が変なことになるので、キチキチに詰めて書いているが、実際はもうちょっとちゃんと改行を挟んでゆとりを持たせて書いている、ということは断っておく。

<!DOCTYPE html>
<html lang="{{ .Page.Language | default "ja" }}" class="js csstransforms3d">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        {{ hugo.Generator }}
        <title>{{ .Title }} {{ default "::" .Site.Params.titleSeparator }} {{ .Site.Title }}</title>
    </head>

{{ define "main" }}
<h1>Hello World</h1>
{{ end }}

とりあえずタブに出てくるサイト名が変わったのがわかるだろうか?これはconfig.tomlを参照している。

テーマはできれば公開したいので、今はあまり弄らないでおいた。

f:id:pop-ketle:20211115135607p:plain

ちょこちょこコードに変更を入れていく。 これは、普段のページがどう書かれるかを書いたものだ。 {{ .Content }}が記事の中身になる(はず)。

{{ define "main" }}
<article>
  {{ .Content }}
</article>
{{ end }}

ところで色々調べてたんだけど、HugoとVuetifyを組み合わせた記事が見当たらないので、Vuetifyを使う計画は止まっている。 なんか相性が悪いというか、HugoかVuetifyどっちか片方で済むんじゃないかという気がしてきている。組み合わせるメリットってあるのか?(この辺りから怪しい空気が漂ってますね...)

ともかく今は最初の目的の一つだった、seleniumを使ったデータ分析コンペの結果の自動スクショで戦績更新ページを作りたい。やろう。

下記コマンドでcontent/ 配下にページが作成される。Hugoはこうやって作成した.mdをhtmlファイルに変換してくれる。

$ hugo new [PAGENAME/~.md]

今回はデータコンペの戦績ページを作成したいので、こんな感じの名前にした。

$ hugo new deta_competitions/index.md

ここから似たファイル名が増えるのでわかりにくくなってしまうが、こんな感じの変更を加えた。これでトップページに作成したページへのリンクが並ぶはずである。 例によってコードブロックの改行タグがおかしなことになっているのでキチキチだが許して欲しい。

{{ define "main" }}
<h1>Hello World</h1>
<h1>記事一覧</h1>
{{ range first 10 .Pages }}
<a href={{ .Permalink }}>{{ .Name }}</a>
{{ end }}
{{ end }}






本当はこの記事を書いた目的は、Kaggleなどの戦績を定期的にSeleniumで自動スクショしておいてくれるポートフォリオを作りたいというものだったのだが、2021年11月16日現在、Kaggleの規約をよく読んでみるとスクレイピングしたらどうなるか、わかってるよね?と書いてあったので泣く泣く断念した。アカウントを消されたら元も子もない。

f:id:pop-ketle:20211116103321p:plain

Terms of Use | Kaggle

ということで、とりあえずヘッダーに幾つかのサイトへの画像リンクを作成した。画像アイコンは割とやっつけなので、出来が良くないのでおいおい綺麗にしていこうと考えている。また、画像ファイルはthemes/UltraPop/static/images/の下に置いておくと以下のようなリンクの書き方で、うまいことHugoがやってくれる。(*あとでhugoコマンドでサイトを生成してみたら画像リンクがうまく貼れていなかったのでこれは嘘です。)

<a href="https://www.kaggle.com/popketle"><img src="/images/kaggle_logo_icon.png" alt="", width="30" height="30"></a>
<a href="https://signate.jp/users/37802"><img src="/images/signate_logo_icon.png" alt="", width="30" height="30"></a>
<a href="https://comp.probspace.com/users/pop-ketle/0"><img src="/images/probspace_logo_icon.png" alt="", width="30" height="30"></a>
<a href="https://atcoder.jp/users/popketle"><img src="/images/atcoder_logo_icon.png" alt="", width="30" height="30"></a>
<a href="https://github.com/pop-ketle"><img src="/images/github_logo_icon.png" alt="", width="30" height="30"></a>
<a href="https://qiita.com/pop-ketle"><img src="/images/qiita_logo_icon.png" alt="", width="30" height="30"></a>

f:id:pop-ketle:20211116103608p:plain

Vuetifyでの開発

そろそろVuetifyでの開発に移りたい。それに伴ってvue系のファイルの置き場所を変えた。 themes/UltraPop/static/配下に作り直した。

また、npm run serve errorがエラーが出るので、次の記事を参考に

node.js - Error message "error:0308010C:digital envelope routines::unsupported" - Stack Overflow

export NODE_OPTIONS=--openssl-legacy-providerをコマンドに打ち込んで解決した。Macはどうもopenssl周りの挙動が怪しくていけない。

これによってvuetify画面が出るようになった。しかし、これをどうすればHugoとくっ付ければ良いのか?まぁ、とりあえずできそうなことを試しにやっていくしかない。人生そういうもの。

f:id:pop-ketle:20211116104837p:plain










長い時間が経ってしまった......

f:id:pop-ketle:20211121062300j:plain

次の記事を参考に進めていったが、うーん、悲しいかな、どうしてもHugoとvueのテンプレートエンジンが競合したり、パス周りがうまくいかなくて厳しいことがわかり始めた。Vueだけならどうにかなりそうなんだけど、Vuetifyを使ってcomponentを作る形で開発していくと同してもパスが通らない。

discourse.gohugo.io

www.michaelgodeck.com

ということで、この方針は諦めてHugoで.jsonファイルを吐き出してそれを読み込んでVuetifyで画面構築しようかなと思う...んだけど、そうするとHugoっているのかな...というわけで色々悩み中。

次回、本編に続く...かな?

色々考えると、既存のHugoのテーマで困ってないし、Notionとか使ってもいいしで、モチベーションの持って行きようがなくて困っちゃうよね。