【Ruby on Rails】アセットパイプラインとはなんぞや（初学者向け）

私は現在、未経験からのエンジニア転職に向けてプログラミングスクールで学習をしている、いしかわと申します。

今回Webアプリケーションの個人開発を進めている際、詰まってしまった**アセットパイプライン**について調べました。
どなたかの参考になれば幸いです。

:::note warn
プログラミング初学者なので、内容に誤り等ある可能性があります
誤りがありましたら教えてくださると幸いです
:::

## アセットパイプラインってなに？
アセットパイプラインは、アプリケーション開発において、JavaScript、CSS、画像などの静的ファイルを効率的に管理、最適化、提供するための仕組みです。主な目的は、ウェブページの読み込み速度を向上させ、ユーザーエクスペリエンスを向上させることです。アセットパイプラインはこれらのファイルを自動的に最小化、結合、キャッシュ管理し、ブラウザへの効率的な提供を補助します。これにより、ウェブアプリケーションのパフォーマンスを向上させることができます。

## 要するになに？
`アセット`:画像やCSSやJavaScriptファイルのリソースのこと
`パイプライン`:アセットを次々に一連の処理を行う仕組み
アセットパイプラインはアセットファイルの**連結**、**最小化**、**コンパイル**を行います

## アセットパイプラインの主要な機能
### アセットの連結
Webブラウザが同時に処理できるリクエスト数には限りがあるため、1つ1つのアセットファイルを取得するのは効率が悪いです
そのため複数ある.cssファイル、.jsファイルを1つにまとめる**連結**を行うことで冗長なリクエストや通信を減らします。

### アセットの最小化
アセットファイルに含まれる空白やコメントを削除し、ファイルを**最小化**することによって、ファイルサイズを縮小し、結果的にダウンロード時間が短縮され、ページの読み込み速度が向上します。これは連結と同時に行われます
これはアプリケーションが大規模であればあるほどパフォーマンスの向上が期待できます
※javascriptの最小化方法はオプションから選んだり独自に指定することが可能
※最小化を「圧縮」と表現することもありますが、これはzipファイルに変換するような圧縮ではありません

### 高級言語から低レベル言語へのコンパイル
`高級言語`:人間がわかりやすいように設計されたプログラミング言語(Sass, ERB)
`低レベル言語`:機械がわかりやすいように設計された言語(JavaScript, CSS)
`コンパイル`:高級言語をコンピュータが実行できる低俗言語に変換すること
人間が理解しやすい`高級言語`のままではブラウザは理解ができないため、`低レベル言語`に変換します(例えばSassをcssに変換します)

### フィンガープリントの付与
`フィンガープリント`:更新のたびアセットファイルの名前に付与される一意なハッシュ値。通常ファイル名にはハッシュ値が含まれていないため、ファイルが更新された場合にブラウザが更新を認識できない可能性がある。ハッシュ値を付与することで、更新を認識して再読み込みができる。
```ruby
# hoge.jsにフィンガープリントを付与すると以下のようなファイル名になる
application-1055d2f9a1a248bf051584d3572c2f2d79d103e956e0fcee48f1cab5cd40472b.js
````

## アセットパイプラインの使い方
### アセットファイルの配置
Railsでは`app/assets/javascripts, stylesheets, images`ディレクトリをアセットファイルの置き場所として推奨しています
推奨している置き場所にアセットファイルおよび`マニフェストファイル`を配置することによって、開発環境においてはは自動的にアセットパイプラインが実行されます
仮に`app/assets/javascripts, stylesheets, images`ディレクトリの配下にサブディレクトリを作成し、そのサブディレクトリにアセットファイルを保存したとしても`assets/`配下のディレクトリは全て検索対象となっています
### マニフェストファイルの配置
`マニフェスト`:読み込むアセットの集まり
`マニフェストファイル`マニフェストが書かれたファイル(`application.js`, `application.css` etc...)
マニフェストファイルにはアセットファイル名と`ディレクティブ`を一緒に記述することで、複数のアセットファイルを連結させ最小化します
通常マニフェストファイルとは`javascript`では`application.js`,`css`であれば`application.css`となります
```js:application.js
//= require rails-ujs  # application.jsに連結を命令
//= require turbolinks # application.jsに連結を命令
//= require_tree .     # 現在のディレクトリに存在するjavascriptファイルをapplication.jsに連結を命令
```
`require`というのは`ディレクティブ`といいアセットファイルに対して行う特定の命令のことをいいます
```
          require:指定したファイルを連結する
     require_self:マニフェストファイル自体の内容を連結する
require_directory:指定したフォルダー内のファイルを連結する
     require_tree:指定したフォルダー内のファイルを再起的に連結する
             link:指定したファイルをコンパイルする（連結はしない）
   link_directory:指定したフォルダー内のファイルをコンパイルする（連結はしない）
        link_tree:指定したフォルダー内のファイルを再起的にコンパイルする（連結はしない）
        depend_on:指定したファイルが変更された場合に再コンパイルする。
             stub:指定したファイルを無視する。

#※requireディレクティブは連結のみを行い、ファイルの最小化はアセットパイプラインによる別のプロセスで自動的に行われます。
```
色々なディレクティブがありますが多様するのは
`require`,`require_self`,`require_tree`の３つです
※`require`ディレクティブは連結のみを行い、ファイルの最小化はアセットパイプラインによる別のプロセスで自動的に行われます。

上記の`application.js`の例で使用している`require_tree`は同じディレクトリにあるjavascriptファイルを全て`application.js`に連結する場合に使用します。これはディレクトリ内にカスタムアセットファイルがある場合に使用します。

application.cssの内容の例は以下のようになります
```scss:application.css
/*
 *= require_tree .
 *= require_self
 */
```
※上から順にディレクティブが命令され結合されます。結合される順番によってjavascriptやcssの設定が上書きされたりするので注意が必要です

### コンパイルされたアセットファイルの参照
アセットパイプラインによってコンパイルされたアセットファイルを参照するにはRailsのヘルパーメソッドである`javascript_include_tag`と`stylesheet_link_tag`を使用します
```erb:application.html.erb
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
```
TurbolinksについてはRailsガイドを参考にしてください

https://railsguides.jp/v6.1/asset_pipeline.html#%E3%82%A2%E3%82%BB%E3%83%83%E3%83%88%E3%81%AB%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%99%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%8F

### アセットパイプラインの使い方

アセットパイプラインによってコンパイル（低レベル言語への変換）されたアセットファイルは`フィンガープリント`が付与されているため通常のタグでは参照することができないです
アセットファイルの参照にはRailsのヘルパーメソッドである`javascript_include_tag`と`stylesheet_link_tag`を使用します。
```ruby:application.html.erb
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
```
## 開発環境と本番環境の挙動の違い
開発環境では迅速なデバッグと変更の反映が重視され、本番環境ではウェブページの読み込み速度と効率が重視されるため、両環境で挙動に違いがあります
### 開発環境
アセットファイルがリクエストごとにコンパイル(リアルタムコンパイル)
されることによって変更内容がリアルタイムで反映され、開発過程でのデバッグがしやすくなります
また、可読性、デバッグのしやすさを考慮してアセットファイルの最小化を行いません
アセットファイルはマニフェストファルに記載されている順番に読み込まれコンパイルされます
開発環境の場合、コンパイルされたアセットファイルには先述した`フィンガープリント`は付与されません
```js:application.js
//= require core
//= require projects
//= require tickets
```
上記のようなapplication.jsが読み込まれた場合、以下のHTMLが生成されます
```erb
<script src="/assets/core.js?body=1"></script>
<script src="/assets/projects.js?body=1"></script>
<script src="/assets/tickets.js?body=1"></script>
```

### 本番環境
デプロイ前にアプリケーションの起動負荷を減らし、処理速度を向上させるためにアセットファイルをプリコンパイルします。これはサーバーの起動時間を減らし、処理速度を向上させます。
また開発環境では連結のみでしたが、本番環境では連結・最小化を行います
開発環境と同じく、アセットファイルはマニフェストファルに記載されている順番に読み込まれコンパイルされます
本番環境の場合、コンパイルされたアセットファイルに`フィンガープリント`が付与されます
```erb
<%= javascript_include_tag "application" %>
<%= stylesheet_link_tag "application" %>
```
上記のようなHTMLによって生成されるコードは以下のようになります
```erb
<script src="/assets/application-908e25f4bf641868d8683022a5b62f54.js"></script>
<link href="/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css" media="screen" rel="stylesheet" />
```

### まとめ
現在、にポートフォリオを作成していますが、自身の理解度が低くつまづくことが多く技術記事を書くことで理解が深まるのではないかと思い記事を書きました
初めての技術記事でしたが、わかっているつもりのことでも言語化したり、深く調べることでより理解度がクリアになるなあと実感しました！逆にわからないことも増えましたがw
拙い文章かつ、誤った内容があるかもしれませんが、そのときは教えていただければ幸いです
ありがとうございました！

## 参考文献

https://railsguides.jp/v6.1/asset_pipeline.html#%E3%82%A2%E3%82%BB%E3%83%83%E3%83%88%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

https://autovice.jp/articles/143

https://blog.mothule.com/ruby/rails/ruby-rails-assets-pipeline-use#%E3%82%A2%E3%82%BB%E3%83%83%E3%83%88%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3%E3%81%AE%E5%85%A8%E4%BD%93%E3%83%95%E3%83%AD%E3%83%BC%E3%82%92%E7%9F%A5%E3%82%8B

https://qiita.com/suzu12/items/d43a06b42246ef10dde3