HugoでBootstrap v5へ移行した時のメモ

# はじめに

Hugoを利用して作成しているWebページがあります。これまではBootstrap v4のソースコードから、scss/_variables.scss を変更して、配色をカスタマイズした上で、buildして生成したbootstrap.min.jsファイルをコピーしていました。

このBootstrapをv5.1.3に移行するために、ドキュメントに従って作業をした際のメモを残します。

# リファレンス

* [https://getbootstrap.com/  -- Installation](https://getbootstrap.com/)
* [https://getbootstrap.com/docs/5.1/customize/sass/ -- Sass](https://getbootstrap.com/docs/5.1/customize/sass/)

# 作業環境

* Ubuntu 20.04 LTS (on VMware Workstation 16 pro)
* Hugo v0.92.2+extended (go install --tags extendedから最新の~/go/bin/hugoを利用)

# 準備作業

Hugoについてはv0.92.2+extendedを使用していて、asciidoctorとsassが利用できるようにしています。

Bootstrapの公式ガイドに従って、まずはgemを利用して、コード一式をダウンロードします。

```bash:gemによるbootstrapの準備
$ gem install --user bootstrap -v 5.1.3
```

ユーザー領域を指定していて、~/.gemrcファイルは空なのでデフォルトの ~/.gem/ruby/2.7.0/gems/bootstrap-5.1.3/ にファイルが配置されています。

これをコピーしても良かったのですが、gemはRailsなどの利用を想定しているように見えましたので、今回は npm を使う事にしました。

themes/mytheme があるので、これを使う前提でコマンドを下記に書いていますが、themesを利用していない場合は、Hugoのプロジェクトディレクトリ直下に、assetsディレクトリを準備して、その中で npm コマンドを実行してください。

```bash:Hugoのscss領域にファイルをコピー
## Hugoプロジェクトのディレクトリ直下から作業開始
$ cd themes/mytheme
$ cd assets/
$ npm install --user bootstrap

## gitで管理しているので新しく作成されたファイルをチェックする
$ git status
...
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        node_modules/
        package-lock.json
        package.json

$ ls node_modules/
 bootstrap/  '@popperjs'/
```

公式ドキュメントに従って作業を進めてみます。

# ディレクトリ構造

公式ガイドにディレクトリ構造が掲載されています。今回のプロジェクトのファイル構造はこんな感じです。

```text:主なディレクトリ構造
<hugo project-top>/
└── themes/
      └── mytheme/
            └── assets/
                   ├── node_module/
                   │         ├── bootstrap/
                   │         └── @popperjs/
                   └── sass/
                         └── my-bootstrap.scss
```

最後の my-bootstrap.scss から、node_module配下にあるscssファイル群を@importしていきます。


# my-bootstrap.scss の編集

公式ガイドに従って、やりたいことができる確認していきます。

```bash:
$ emacs bootstrap.scss
```

公式ガイドには、Option. A として、コード全体を@importしてからカスタマイズする方法が冒頭に説明されていますが、色を変化させたいなどのデフォルト値を変更したい場合にはうまく機能しません。

今回は、Option. B で説明されているように、デフォルト値を任意に変更することができる方法を採用しました。

最終的なコードは次のようになっています。

```scss:my-bootstrap.scss
// my-bootstrap.scss
// Reference: https://getbootstrap.com/docs/5.1/customize/sass/#importing
//
// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)
@import "../node_modules/bootstrap/scss/functions";

// 2. Include any default variable overrides here
// scss-docs-start color-variables
$blue:    #9edefe !default;
$indigo:  #345a6e !default;
$purple:  #6372c1 !default;
$pink:    #d63384 !default;
$red:     #dc3545 !default;
$orange:  #fd7e14 !default;
$yellow:  #edf68d !default;
$green:   #289785 !default;
$teal:    #20c997 !default;
$cyan:    #0fa8a8 !default;
// scss-docs-end color-variables

$primary:       $cyan !default;
$info:          $blue !default;
$danger:        $orange !default;
$link-color:                              darken($green, 10%) !default;
$link-hover-color:                        darken($link-color, 25%) !default;

// 3. Include remainder of required Bootstrap stylesheets
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/mixins";
@import "../node_modules/bootstrap/scss/root";

// 4. Include any optional Bootstrap CSS as needed
@import "../node_modules/bootstrap/scss/utilities";
@import "../node_modules/bootstrap/scss/reboot";
@import "../node_modules/bootstrap/scss/type";
@import "../node_modules/bootstrap/scss/images";
@import "../node_modules/bootstrap/scss/containers";
@import "../node_modules/bootstrap/scss/grid";
@import "../node_modules/bootstrap/scss/helpers";

// 5. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`
@import "../node_modules/bootstrap/scss/utilities/api";

// 6. Add additional custom code here
``` 

最後のステップで何を追加でimportするべきか、まだはっきりしていませんが、これで試していきます。

# Hugo での利用

最終的には作成したファイルをHugoから次のようなコードを layouts/partials/head.html から次のように参照しています。

```html:Hugoからの参照（layouts/partials/head.html）
  <!-- bootstrap5 -->
  {{ $style := resources.Get "sass/my-bootstrap.scss" | toCSS | minify | fingerprint }}
  <link rel="stylesheet" href="{{ $style.Permalink }}" />
 {{ $jscode := resources.Get "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js" }}
  <script src="{{ $jscode.Permalink }}" ></script>
```

この head.html は、themes/mytheme/layouts/_default/baseof.html から次のように読み込まれています。

```html:baseof.html
<!DOCTYPE html>
<html lang="{{ .Site.Language.Lang }}">
<head>
   {{ partial "head.html" . }}
 </head>
<body>
  {{ partial "header.html" . }}
  <main class="container">
  {{ block "main" . }}{{ end }}
  </main>
  {{ partial "footer.html" . }}
</body>
</html>
```

ここら辺は環境によって異なると思いますが、baseof.html が起点です。

# 実際に使ってみた不具合

オリジナルの node_modules/bootstrap/scss/bootstrap.scss では全てのモジュールを読み込んでいますが、ここで作成したmy-bootstrap.scssは一部しか@importしていません。

そのため、例えば、このままでは、.nav-item, .navbar 等を指定しても list-style: none などのCSSが適用されません。また .navbar-toggler を正常に動かすためには、_transitions.scss も読み込む必要がありました。(.collapseが定義されているため)

ドキュメント や node_modules/bootstrap/scss ディレクトリを確認して、必要なモジュールを読み込む必要があるので注意が必要です。

```scss:my-bootstrap.scssに追加した内容
// 6. Add additional custom code here
@import "../node_modules/bootstrap/scss/nav";
@import "../node_modules/bootstrap/scss/navbar";
@import "../node_modules/bootstrap/scss/transitions"; // It's essential for navbar-collapse
@import "../node_modules/bootstrap/scss/tooltip";
@import "../node_modules/bootstrap/scss/popover";
@import "../node_modules/bootstrap/scss/tables";
@import "../node_modules/bootstrap/scss/list-group";
@import "../node_modules/bootstrap/scss/pagination";
@import "../node_modules/bootstrap/scss/breadcrumb";
@import "../node_modules/bootstrap/scss/carousel";
```

# さいごに

元々のbootstrapのプロジェクト全体をビルドする方法も悪くはないのですが、今回の方が必要なモジュールだけを組み込めて、かつ、変更も hugo server の仕組みを使って簡単に確認できるので作業効率は上がりそうです。