ERB が使われている既存の web システムへ Slim 導入に至るまでの話

これは [Livesense Advent Calendar 2022 DAY 12](https://adventar.org/calendars/7971) の記事です。

## はじめに
ビューに [ERB](https://ja.wikipedia.org/wiki/ERuby) が使われている web システムへ [Slim](https://github.com/slim-template/slim/blob/master/README.jp.md) 導入に至るまでにあったことを記載しています。
[Ruby On Rails](https://rubyonrails.org/) で構築された web システムであることを前提としています。
[Slim](https://github.com/slim-template/slim/blob/master/README.jp.md) 導入時の判断材料の一つになれば幸いです。

## Slim とは何か？
- [Ruby On Rails](https://rubyonrails.org/) に対応した軽量、高速なテンプレートエンジン
  - 雛形(テンプレ)とデータで表現される入力データを合成して出力するソフトウェアコンポーネント

## なぜ既存の web システムに Slim を導入したか？
もともと ERB が使われていた web システムでしたが、下記のような声が上がり、導入を検討し始めることになりました。

- HTML に Ruby を埋め込む形になっていて見難い ( HTML と Ruby のゴチャ混ぜを解消したい)
- 少ないコード量で書きたい
- 株式会社リブセンスが提供する他のサービスでも Slim が使われているものもあるが、なぜ当該システムでは ERB なのか

ですが、上記だけでは Slim が導入必須であるとは言い難い為、導入するなら **ビューは Slim でなければならない理由** が欲しいと思い、主に下記のような観点で調べてみました。

1. Slim を導入し、少ないコード量になれば生産性は向上するのか
1. Slim を導入すればページ表示速度は向上するのか

結論から言うと Slim を導入したからといって上記が特別に向上するようなことはありませんでした。

**1** に関しては確かに少ないコード量にはなりますが、ビューを見たときに脳内で HTML に変換する作業が発生したり、ビュー内での広い制御構造の後に何かしらのコードを記述する場合、インデントがズレないように常に意識して細心の注意を払う必要があります。
インデントがズレると制御構造の内側にあるべきコードが外側になる為、ビューで表示されるべきものが表示されなかったり、エラーになります。

**2** に関しては体感する程の表示速度向上は見受けられず、また実際に数値を見ても特に大きな変化は見られませんでした。


次に **ビューは ERB のままでなければならない理由、ERB のほうが良い理由** を考えます。

1. 少ないコード量で書けるのが Slim の特徴ではあるが、基本的な文法から外れるようなコードを記述する場合は(慣れない間は)都度調査する必要がある
1. (慣れない間の)調査時間を鑑みると記述量を減らしたことで短縮した時間を調査時間が上回ってしまうかもしれない

というような点を危惧し、ERB のままのほうが良いかとも考えましたが、下記の理由により Slim を導入することにしました。

1. Slim に慣れているエンジニアが多かった
    - Slim が嫌いなエンジニアがいなかった
1. Slim に関する良し悪しの知見が欲しかった
1. サービスが小さい間(試せる間)に試しておきたかった

Slim に慣れているエンジニアが多いこともあり、危惧したような **記述量を減らしたことで短縮した時間 < 調査時間** となるケースが少ないこととメリットがデメリットを上回りそうと考え、導入することにしました。


## Slim を導入して良かったこと

1. HTMLの開始タグ、終了タグのどちらか一方の記述忘れ解消
1. HTMLの開始タグと終了タグのインデントのズレ解消
    - 開始のときは半角スペース4つだったものが終了のときは半角スペース6つになっているということが絶対に発生しない
1. 少ないコード量になったこと、HTML と Ruby のゴチャ混ぜが無くなったことによる可読性向上
    - ただし、コードの内容によっては理解するまで時間が掛かるケースもある

**1** に関しては Slim 導入前、残念ながら `</div>` はあるものの、それに対する `<div>` がないという箇所が1箇所だけありました。
ただ、`</div>` があるだけでレイアウト崩れが発生しているわけでもなかった為、Slim 導入に至ってなければ延々と気付かなかった可能性はあります。

では、どうして気付けたのか・・・！？

それは後述する erb2slim で変換がうまくいかなかったからです。

**２** に関しては Slim はインデントすることで、その内側にコードがあるものとして解釈し、条件式やループに対する `end` であったり、終了タグを記述する必要がないので、**ビュー内でインデントがズレている、インデントがズレていることによる可読性低下**ということは発生しません。
ズレていれば表示内容が意図しないものであったり、エラーになります。


## Slim 導入時に気をつけるべきポイント

ビューに ERB が使われているシステムへ Slim を導入する場合、 erb2slim を使って変換することになりますが、主に下記のようなケースにおいて一発変換できない為、手動で修正しなければならないことも考慮しておく必要があります。

1. `<% %>` or `<%= %>` の間に改行、インデントがあるケース
1. ヒアドキュメント
1. ERB 内に記述された JavaScript
1. HTML の開始タグと終了タグをセットで記述するものに対してどちらか 一方しかないケース
    - 例: 前述した `</div>` に対する `<div>` がない等

開始タグと終了タグのどちらか一方しかないのは構造上の問題である為、変換不可能なのは当然として、その他が多いと手動修正に時間が掛かることは念頭に置いておく必要があります。

## 予期せぬハマリポイント(ハマってしまったこと)

ローカル環境(自身のPC)で Slim を使って開発しているときは問題ありませんでしたが、ステージング環境へデプロイすると何故かレイアウトが崩れるという事態が発生しました。
中央に表示されるべきログイン画面が左側へ寄ったり、その他諸々 CSS が有効になっていない状態が発生しました。

ローカル環境では正常に動作しているのにステージング環境へデプロイすると上記のようになるのは何故だろうと暫く考え、

**レイアウトが崩れる -> CSS が正常にビルドされない、、、ということは・・・** 💡


という感じで下記の原因に辿り着きました。

### 原因

`tailwind.config.js` (という Tailwind CSS のカスタマイズ用の設定ファイル)に **.slim** が含まれていないことが原因でした。
  ```js:tailwind.config.js
    module.exports = {
      content: [
        './app/views/**/*.html.slim' // ← これを記述する必要があった
      ]
    }
  ```
ローカル環境で上記を含めなくても動作していたのは ERB のときにビルドされたものが残っていたからです。

原因が判明し、その上で `tailwind.config.js` へ上記を含めずにローカル環境でも同じようにビルドしたところ、ステージング環境同様、レイアウトが崩れる状態になりました。😅

その後、`tailwind.config.js` へ上記を含めてステージング環境へデプロイしたところ、レイアウトが崩れることなく、正常に表示されました。

## まとめ

- ERB と比べて記述量が少なくなる
  - 人によってはこれがシンプルと感じられる
- HTML の開始タグ、終了タグのどちらか一方しかないということや終了タグ、`end` 記述時のインデントのズレを意識しなくても良くなる
  - ただし、開始時はインデントを意識する必要がある
- erb2slim では一発変換不可能なところもあることを念頭に置いておく
- 拡張子(`.erb`)を指定して何かを設定している場合は、そちらへ slim を追記 or 変更することを忘れないようにする
  - 今回のケースであれば `tailwind.config.js` の `.erb` を `.slim` へ変更すること
- Slim によって記述量を減らしたことで短縮した時間 < 調査時間 となるような場合は **Slim 導入を控える**