静的サイトジェネレータ (SSG)

ドキュメンテーションに利用できる静的サイトジェネレータ（Static Site Generator）について調べている。まだまだ道半ばであるが、ある程度まとまってきたので現時点の資料を公開する。（今後も追記予定。）

### 要件

少なくとも以下の機能があるものを調査対象とする。

- Markdownでの記述
- デザイン（テンプレート）切り替え
- ページ階層（折り畳み対応ナビゲーションバー、パンくずリストの表示）
- ページ内検索
- 多言語化（できれば翻訳文言の管理）
- ソースコードのシンタックスハイライト、ダイアグラムの表示（MermaidJSなど）
- ローカル（Webサーバーなし）での参照

### 候補

少し検索してみただけでも多くのプロダクトが出てくる。詳細は調べられていないが、有名どころは以下の通り。

- [Hugo](https://gohugo.io/)
- [Docusaurus](https://docusaurus.io/)
- [MkDocs](https://www.mkdocs.org/)
- [VuePress](https://vuepress.vuejs.org/)
- [Sphinx](https://www.sphinx-doc.org/)
- [Pandoc](https://pandoc.org/)

参考

* [Static Site Generators - Top Open Source SSGs | Jamstack](https://jamstack.org/generators/)
* [Our Top 11 picks for Static Site Generators (SSGs) in 2021 | Hygraph](https://hygraph.com/blog/top-12-ssgs-2021)
* [ドキュメント作成に向いている静的サイトジェネレータはどれ？ - Wiz テックブログ](https://tech.012grp.co.jp/entry/2021/08/27/102514)

### [Hugo](https://gohugo.io/)

Go言語で実装されており、高速な動作を謳い文句としている。

#### インストール

Windowsの場合はScoop (もしくはChocolaty) でインストールするのが簡単である。

```
scoop install hugo
```

参考：[Install Hugo](https://gohugo.io/getting-started/installing/#scoop-windows)

#### プロジェクト作成～ビルド

[Quick Start](https://gohugo.io/getting-started/quick-start/)のStep 2: Create a New Site～Step 7: Build static pagesの通りに進めればよい。

#### プロジェクトのディレクトリ構成

代表的なディレクトリは以下の通り。詳細は[Directory Structure](https://gohugo.io/getting-started/directory-structure/)を参照。

| ディレクトリ                                                 | 説明                                                         |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| [`archetypes`](https://gohugo.io/content-management/archetypes/) | 新しいcontentを作成するときのテンプレートを入れる。          |
| [`content`](https://gohugo.io/content-management/organization/) | サイトのcontentを入れる。直下のディレクトリが[Content Section](https://gohugo.io/content-management/sections/)となる。 |
| [`layouts`](https://gohugo.io/templates/)                    | home page, list page, single pageなどの各ページ用のテンプレートを入れる。 |
| public                                                       | ビルド結果の出力先                                           |

#### Contentの管理

##### サイト構造

contentディレクトリの構造がサイトの構造に反映される。

```
content
├── _index.md          <-- homepage (https://example.com/)
└── posts              <-- section (because it is the first-level directory)
    ├── first.md       <-- single page (https://example.com/posts/first/)
    └── tech           <-- section (becuase it contains _index.md)
        └── _index.md  <-- list page for section (https://example.com/posts/tech/)
        └── second.md  <-- single page (https://example.com/posts/tech/second/)
```

参考

* [Organization of Content Source](https://gohugo.io/content-management/organization/#organization-of-content-source)
* [Path Breakdown in Hugo](https://gohugo.io/content-management/organization/#path-breakdown-in-hugo)
* [Content Sections](https://gohugo.io/content-management/sections/)

##### [Taxonomy](https://gohugo.io/content-management/taxonomies/)

Contentをグループ化するための分類機能。

Site Configにて分類（Taxinomy）の一覧を定義する。

```toml
[taxonomies]
  tag = 'tags'
```

Front Matterにて、各分類についてContentが属するグループ（Term）を定義する。

```toml
tags = ['Development', 'Go', 'fast', 'Blogging']
```

#### 多言語化

##### Content File (/content/**)

コンテンツの翻訳を管理する方法は2つある。（参考：[Translate Your Content](https://gohugo.io/content-management/multilingual/#translate-your-content)）

* `article.en.md`、`article.fr.md`のようにファイル名の接尾辞に言語コードを入れる。
* `/content/en/about.md`、`/content/fr/about.md`のようにディレクトリ名に言語コードを入れる。

##### Layout File (/layout/**)

layout内のテンプレートを多言語対応するには `i18n/{言語コード}.toml` に記載した翻訳文言をi18n関数（`{{ i18n "home" }}`のような記述）で参照する。（参考：[Translation of Strings](https://gohugo.io/content-management/multilingual/#translation-of-strings)）

#### モジュール

Hugoはstatic、contentなどのコンポーネントをモジュールにまとめて、自由に組み合わせて利用できる仕組みとなっている。モジュールの実体はGo Moduleで動いているとのこと。

管理用のCLIコマンド（`hugo mod xxx`）が用意されている。Moduleの設定は`config.toml`の`imports`以下に記録される。

参考：[Hugo Modules](https://gohugo.io/hugo-modules/)

#### ドキュメンテーション用テーマ

[Docsy](https://github.com/google/docsy)、[Book](https://github.com/alex-shpak/hugo-book)、[Learn](https://github.com/matcornic/hugo-theme-learn)など様々なテーマが公開されている。

参考：[Twelve Amazing Free Hugo Documentation Themes | CloudCannon](https://cloudcannon.com/blog/twelve-amazing-free-hugo-documentation-themes/)

### [Docsy](https://www.docsy.dev/) (Hugoテーマ)

技術文書向けのHugoテーマ

#### インストール

(1) Hugo Moduleとして追加、(2) Git submoduleとして追加、(3) ファイルコピーで追加 の3通りの方法がある。Docsyのバージョンアップのことを考えると、(1) Hugo Moduleを使うのが賢明である。

参考

* [Installation options](https://www.docsy.dev/docs/get-started/#installation-options)
* [Update Docsy](https://www.docsy.dev/docs/updating/)

Hugo ModuleとしてDocsyを使うには[自力でモジュールを追加する方法](https://www.docsy.dev/docs/get-started/docsy-as-module/start-from-scratch/)の他に、[プロジェクトのひな形をコピーする方法](https://www.docsy.dev/docs/get-started/docsy-as-module/example-site-as-template/)もある。後者の方がコンテナで動かすためのdocker-composeファイル等も含まれるため、簡単である。

参考：[Use Docsy as a Hugo Module](https://www.docsy.dev/docs/get-started/docsy-as-module/)

#### ドキュメントをプレビューする

Windowsの場合は、コピーしたひな形プロジェクト（[Docsy example site](https://github.com/google/docsy-example)）をVisual Studio Code (WSL) で開き、以下でコンテナを起動する。

```bash
docker-compose up
```

コンテナ内で`hugo server`が実行され http://localhost:1333 にアクセスするとライブプレビューを見ることができる。

参考：[Running a container locally](https://github.com/google/docsy-example#running-a-container-locally)

#### ドキュメントをビルドする

プレビューをバックグラウンドで動かしたまま、同コンテナでビルドを実行するか、

```bash
docker-compose up -d
docker-compose exec site hugo
```

コンテナを起動して`hugo build`を実行すればよい。

```bash
docker-compose run site build
```

publicディレクトリにビルド結果が保存される。

#### ローカルで参照可能なファイルをビルドする

デフォルト設定でビルドすると、ビルドしたファイルをローカルで直接ブラウザで開いても、リソースの読み込みやページ間のリンクが上手く動かない。ローカルで動くようにするには下記の設定を`config.toml`に入れればよい。

```toml
relativeURLs = true
uglyURLs = true
```

[relativeURLs](https://gohugo.io/content-management/urls/#relative-urls)を`true`にすると相対パスになり、[uglyURLs](https://gohugo.io/getting-started/configuration/#uglyurls)を`true`にするとリンクを出力するときにファイル名（index.htmlなど）を省略しなくなる。

参考

* [How can I force HUGO to generate relative paths for everything? - support - HUGO](https://discourse.gohugo.io/t/how-can-i-force-hugo-to-generate-relative-paths-for-everything/24168/4)
* [How to make hugo generate links with "/index.html" instead of simply "/" by the end of the link - support - HUGO](https://discourse.gohugo.io/t/how-to-make-hugo-generate-links-with-index-html-instead-of-simply-by-the-end-of-the-link/24140)

#### ページ内検索の設定を変更する

Google Custom Search Engine、Algolia DocSearch、Lunrのいずれかを利用できる。LunrはJavaScriptでのローカル検索のため、非公開サイトでも利用可能である。（ただし、ビルドしたファイルをブラウザで参照する場合は動作しない。）

参考：[Site search options](https://www.docsy.dev/docs/adding-content/navigation/#site-search-options)