Hugo: a static-site generator

Ben Hoyt

Hugo:静的サイトジェネレーター

原文は Ben Hoyt により に公開されました。 このブログを購読する

静的サイトジェネレーターは、マークアップ言語で書かれたページコンテンツを完全にレンダリングされたHTMLへと変換し、開発者がその成果物をアップロードしてウェブサイトをシンプルかつ安全に公開することを容易にする。本稿では、Goで書かれ速度に最適化された静的サイトジェネレーターであるHugoを取り上げる。Hugoは柔軟なツールで、シンプルなブログからプロジェクトのドキュメント、大規模なニュースサイト、さらには行政サービスまで、さまざまな用途に合わせて設定できる。

背景

静的サイトジェネレーターは、おそらくHTMLの発明とともに存在してきた。ほとんどのサイトには共通のヘッダーやフッターがあり、サイト運営者はそれを各ページに手作業でコピー&ペーストしたくはない。当時は、開発者がHTMLを繋ぎ合わせるために数十行程度のPerlやBashの独自スクリプトを書くことが一般的だっただろう。その方法でも確かに機能するが、今日の静的サイトジェネレーターは単純な自作スクリプトよりも高速で強力だ。

多くのサイトでは、共通ヘッダー(など)をページが表示されるたびに動的にレンダリングすることで処理している。たとえば、データベースに接続したPHPを使う方法だ。2020年現在であれば、開発者はコンテンツを提供するHTTP APIに接続されたReactフロントエンドを使うことの方が多いかもしれない。しかし、サイトが提供すべきものがほとんど静的なコンテンツだけでよい場合、これらの構成はいずれも過剰である。

個人サイトやブログの多く、またプロジェクトや企業のドキュメントサイトも、静的に生成することが可能だ。事前にレンダリングされたHTMLを提供する方が、動的にレンダリングされたコンテンツを提供するよりも高速で信頼性が高い。Wikipediaは静的ウェブサイトが提供する利点として次のようなものを挙げている。

  • 動的ウェブサイトと比較してセキュリティが向上する(動的ウェブサイトは脆弱性がある場合にウェブシェル攻撃のリスクにさらされる)
  • 動的ウェブサイトと比較してエンドユーザー向けのパフォーマンスが向上する
  • データベースやその他のアプリケーションサーバーといったシステムへの依存が少ない、あるいはまったく依存しない

もちろん、一部のウェブサイト(とりわけウェブアプリケーション)では常に動的コンテンツが必要になる。記事の内容自体は静的であるLWNでさえ、ログイン済みの購読者と未ログインの訪問者とで異なるコンテンツを提供する必要がある。したがって、動的サーバーやAPIの需要がなくなることはない。しかし、サイトのコンテンツが静的で公開されている場合や、動的コンテンツをクライアント側で処理できる場合には、静的サイトジェネレーターによってシステムを大幅に簡素化できる。

静的サイトジェネレーターは比較的作りやすいため、オープンソースの選択肢が数多く存在する。主要なプログラミング言語はいずれもそれなりに人気のあるツールを提供しており、たとえばRubyのJekyll、PythonのPelican、JavaのJBake、PHPのSculpin、JavaScriptのHexoなど、他にも数百種類がある。ここでは、活発に開発が続けられ、よくメンテナンスされているオープンソースプロジェクトであるHugoを取り上げる。

Hugoは2013年にSteve Francia(現在はGoのコアチームのメンバー)によって作られたが、2015年にBjørn Erik Pedersenがリード開発者を引き継いだ。プロジェクトはGitHubでホストされている。現在はコメントを除いて約43,000行のGoのソースコードからなり、寛容なApache License 2.0の下でライセンスされている。もちろんHugo自体で構築された充実したドキュメントサイトも用意されている。このプロジェクトにはコミュニティからの関わりも多く、比較的トラフィックの多いディスカッションフォーラムや、ユーザーから投稿された多数のテーマがある。Pedersenは2017年に、Hugoのインフラ(ただし開発ではない)には企業スポンサーがついていると述べた。「Netlifyがサイトを無料でホストし、Discourseがフォーラムを運営してくれています。ビルドはTravis、Appveyor、CircleCIです。それ以外にスポンサーはいません

サイトジェネレーターが何のプログラミング言語で書かれているかは、あまり重要ではない(筆者自身はJekyllを使っているが、Rubyを書く必要に迫られたことはない)。とはいえ、開発者は自分が馴染みのある言語で書かれたツールを好む傾向がある。Hugoを使う場合でも、開発者がGoを書く必要が生じることはおそらくないが、テーマを構築したりカスタマイズしたりする場合には、GoのHTMLテンプレート構文に少し触れる必要があるかもしれない。

BuiltWithによれば、Hugoの利用は過去3年間で急激に増加している。リニューアルされたSmashing Magazineのサイト1PasswordサポートサイトブログLet's Encryptのウェブサイト、そして米国政府のDigital.govサイトなど、いくつかの著名なプロジェクトで使われている。

仕組み

オプションなしで実行すると、hugocontentサブディレクトリ内のMarkdownファイルを走査し、レンダリングされたHTMLをpublicというサブディレクトリに出力する。これらはすべて設定可能で、デフォルトの設定ファイルはプロジェクトのルートにあるconfig.tomlである。出力はテーマに従ってレンダリングされ、テーマとは生成されるHTMLを正確に定義するいくつかのGoのHTMLテンプレートのことだ。テーマにはCSSのスタイルや、テーマに必要な画像やJavaScriptファイルも含まれる。

本稿を執筆する前に、筆者は3つの記事と「About」ページからなるシンプルなテストサイトを立ち上げた。個人サイトやブログで使いそうな典型的な構成だ。テーマを選び、Hugoを設定し、ダミーコンテンツを追加するのに約30分かかった。Hugoは、主要なOSのパッケージマネージャー、GitHub上のビルド済みバイナリ(Linux、各種BSD、macOS、Windows向け)、あるいはソースからのビルドでインストールできる。Hugoの場合、ソースからのビルドはGoをインストールし(まだインストールされていなければ)、プロジェクトをクローンしてgo buildと入力するだけで済む。筆者のマシンでは、クローンからhugo versionの実行まで約20秒だった。

開発中はhugo serverと入力するとローカルウェブサーバーが起動し、レンダリングされたコンテンツをRAMから配信する。このモードでは、Hugoはファイルを自動的に監視し、必要に応じてHTMLを再ビルドする。レンダリングされたページには、コンテンツが変更されるとすぐにウェブブラウザで自動的にリロードするためのJavaScriptまで含まれている(ウェブソケットを使ったLiveReloadによる)。Hugoの組み込みサーバーは本番利用可能なnet/httpサーバーをベースにしているが、デプロイ時にはレンダリング済みファイルを事前にビルドしてAmazon S3のような静的サイトホストにアップロードするか、NGINXのような通常のウェブサーバーの背後で配信する方が通常はシンプルだ。

他の静的サイトジェネレーターと同様に、Hugoはページにシンプルなファイル形式を採用しており、YAML形式の「front matter」とMarkdownコンテンツとが---の行で区切られている。以下は、筆者のサンプルサイトの最初の投稿の内容である。

---
title: "First Post"
date: 2020-07-06T09:33:48+12:00
categories:
- Development
---

The quick brown fox jumps over the lazy dog. Ee equals em cee squared.
Let's try a [link](https://benhoyt.com/) and **some bold text**.

Another paragraph. Hugo seems to be working. Writing Markdown is nice.

Hugoのテーマテンプレートがどのようなものかイメージしてもらうために、筆者のテストで使用したSohoテーマに含まれるsingle.htmlテンプレートを紹介する(単一のブログ記事をレンダリングするものだ)。

{{ define "main" -}}
<div class="post">
  <h1>{{ .Title }}</h1>

  {{ if ne .Type "page" -}}
  <div class="post-date">
    <time datetime="{{ .Date.Format "2006-01-02T15:04:05Z0700" }}">
        {{ .Date.Format "Jan 2, 2006" }}
    </time>
    &middot; {{ .ReadingTime }} min read
  </div>
  {{- end }}

  {{ .Content }}
</div>
{{- end }}

Hugoはページを分類するさまざまな方法である「taxonomies(タクソノミー)」をサポートしており、タクソノミーごとに、そのタクソノミーが割り当てられたすべての記事を一覧するページを作成する。デフォルトでは「tags」と「categories」のタクソノミーが作成され、たとえば筆者のテストサイトでは「Development」カテゴリがそれにあたる。ドキュメントでは、タクソノミーの並べ替えやメタデータの追加など、さまざまな方法が紹介されている。

このツールは、レンダリングされたコンテンツ内のページURL(「permalinks」)を制御するさまざまな方法をサポートしており、デフォルトの/:section/:filename/では/posts/third-article/のようなURLが生成される。:sectionの部分はcontent内のサブディレクトリ名(例:posts)に由来し、:filenameはコンテンツの元となったファイルの拡張子を除いた名前である。これらの「ディレクトリURL」は、レンダリングされたHTMLファイルをインデックスファイルを含むディレクトリとして作成することで実現されている。すなわち/posts/third-article/index.htmlのようにである。

Hugoのより高度な機能の一つに「shortcodes(ショートコード)」と呼ばれるものがある。これはHTMLの小さなスニペット(パラメータ付き)で、HTMLに直接頼ることなくMarkdownの限られた機能を補強するために使える。組み込みのショートコードは多数あり、たとえばgist(GitHub Gistの埋め込み)、highlight(シンタックスハイライトされたコード)、youtube(YouTube動画の埋め込み)などがある。たとえば、次のようなショートコードは

{{< youtube w7Ft2ymGmfc >}}

次のようなHTML出力を生成する。

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe src="https://www.youtube.com/embed/w7Ft2ymGmfc?autoplay=1"
      style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;"
      allowfullscreen title="YouTube Video"></iframe>
</div>

Hugoには他にも、記事内の見出しから目次を生成する機能、代替のマークアップ形式(デフォルトはMarkdown)、CSSやJavaScriptを前処理するためのパイプライン、画像のリサイズや切り抜きを行う画像処理コマンドなど、より高度な機能が含まれている。

Hugoは高速であることを売りにしており、ホームページでは「1ページあたり1ミリ秒未満、平均的なサイトは1秒未満でビルドされる」と謳っている。Smashing Magazineの7500ページからなるサイトは、どうやら約13秒でビルドされたようだ。この速度は、Goというネイティブバイナリにコンパイルされる言語(Pythonのようなバイトコードインタープリタ言語とは対照的に)で書かれていることに一部起因するが、長年にわたってコントリビューターが行ってきたさまざまなベンチマークやパフォーマンス改善の取り組みにもよるところが大きい。たとえば、2020年1月にリリースされたバージョン0.63のリリースノートを参照されたい。

一般的に静的サイトジェネレーターでは、コンテンツの執筆者は開発者であるか、少なくともテキストエディタ、Markdown、Gitの使用に習熟している必要がある。しかし、ウェブホストであるNetlifyは、非開発者でもWYSIWYGエディタを使って寄稿できるNetlify CMSというオープンソースツールを提供しており、このツールは裏側でGitリポジトリにコミットを行う。Hugoのドキュメントには、他にも同様のツールのリストが掲載されている。

ホスティングの選択肢

静的サイト生成では、開発者はレンダリングされた成果物を任意のホストやウェブサーバーでホストすることを選択できる。一般的な選択肢としては、GitHub Pages、Amazon S3、Netlify、あるいはCaddyやNGINXといったウェブサーバーを使ったセルフホスティングがある。Hugoにはさまざまな選択肢についての詳細なセットアップ情報をまとめたドキュメントページがある。

筆者のテストサイトでは、Amazon S3(前面にAWSのCloudfront CDNを配置)を採用することにした。セットアップは非常に簡単で、月に数ドルで何百万ものページビューを処理できる。もちろん、クラウドをまったく使わず、手元にあるサーバーでホストすることも可能だ。安価なサーバーでも、1秒あたり数千件の静的ファイルリクエストを処理できるだろう。

継続的インテグレーション(たとえばGitHub Actions)を使って、サイトのGitリポジトリへのコミットごとにHugoのビルドを実行し、レンダリングされたバージョンを常に最新の状態に保つことも容易だ。

まとめ

Hugoには公開されたロードマップや固定的なリリーススケジュールはないようだ。ここ数年は月に1回程度のペースでリリースが行われ、その間にバグ修正リリースが挟まれている。2018年7月にはPedersenが「1.0への道」について語ったが、現時点ではメンテナらは0.x台のバージョン番号で満足しているようだ。リリース名はしばしばユーモラスで、「Christmas Edition」や「40K GitHub Stars Edition」といったものがある。

静的サイトジェネレーターは、コンテンツの大部分が静的なウェブサイトを構築・デプロイするための比較的シンプルな手段だ。Hugoの速度、寛容なライセンス、そして豊富な機能は、小規模な個人サイトであれ大規模でコンテンツの多いサイトであれ、開発者にとって魅力的な選択肢となっている。総じて、Hugoは今後も注目に値する活発なプロジェクトだ。

[このトピックを提案してくれたJim Garrison氏に感謝する。]

この記事は「muse-spark-1.2-contributor」を使用して翻訳されました。

コメント