Rails資産を活かして、webpackによる Vue (Single File Components) 共存を試みた際の調査まとめ

Rails と Vue の共存をしたい。
できれば以前のコードを活かしたい。
既存アプリケーションをいきなりSPAにするには敷居が高い。

そう考えて調査したことをまとめました。

大きな流れではVue単一コンポーネントやSPAへ置き換えていく方向で検討したいが、既存のRails/Hamlで生成しているテンプレートも資産として捨てがたい。という方向け。


# 2つのアセットパイプラインを理解する
まずは、次の２つのアセットパイプラインを理解する必要がありました。
いままでRailsの恩恵を受けて、理解せずにきましたが、ここできちんと理解できたのはよかったです。

端的にいうと、
1. webpack : Rails5.1 で対応し、Rails6 からデフォルトになっている
2. Sprockets : Rails 5 までのデフォルト
であることを理解する必要があります。
Rails5.2 から Rails6 への移行時には、webpack 対応を行うきっかけにもなります。Rails5.1以上であれば webpacker(=Railsのwebpack対応) をいれておいてから Rails6へUpgradeすることも可能です。

また、webpack と Sprockets は並存が可能です。
（SprocketsにJavaScriptを含める形での並存が可能）


## 1. webpack
webpack を理解する際に、下記が参考になりました。
端的にいうと、webpackは、点在しているJavaScriptファイルをまとめあげて、クライアントサイドへまとめて配信できる状態を作ります。JavaScriptファイル以外にCSSなども含めることができます。

これにより、SASSやSprocketsで行なっていることが重複するため、置き換えが可能になります。しかし既存コードがSprocketsを利用している場合は、webpack側へ移行しなければならないため、移行コストがかかります。

- Webpackってどんなもの？
    - https://qiita.com/kamykn/items/45fb4690ace32216ca25
- Rails: webpack(er)に乗り換える25の理由（翻訳）
    - https://techracho.bpsinc.jp/hachi8833/2020_04_10/90859
- Vue.jsのコンポーネント化の方法まとめ（rails+webpacker+vue.js）
    - https://qiita.com/Hijiri-K/items/992cd0abc19892a4eede
- Webpackerを導入してから外すまでをふりかえる
    - https://tech.misoca.jp/entry/2019/02/22/110000
- Rails に Webpack と Vue を導入しました！
    - https://note.com/campfire_dev/n/n1686059962b5

## 2. Sprockets
Sprocketsも、すべてのJavaScriptファイルや、すべてのCSSファイルを、それぞれひとつのファイルにまとめあげます。application.js に `// =require ...` と書くのは、そのためです。

下記が参考になります。

> アセットパイプラインはsprockets-rails gemによって実装され、デフォルトで有効になっています。
 - [Rails Guide アセットパイプライン v6](https://railsguides.jp/asset_pipeline.html)

- Rails 6: Webpacker+Yarn+Sprocketsを十分理解してJavaScriptを書く: 前編（翻訳）
    - https://techracho.bpsinc.jp/hachi8833/2020_01_16/85940
- Rails Sprocketsとのお別れの仕方 - 最初の一歩 -
    - https://tech.smarthr.jp/entry/2017/02/21/193000

## まとめたファイル application.js
webpack と Sprockets が共存しており、どちらもJavaScriptを管理していると、application.js は２つになります。

- app/assets/javascripts/application.js : Sprockets 
- app/javascript/packs/application.js : webpack


# 導入方法の検討

さて、ここからが選択肢の検討です。

## 選択肢は３つ
大きく分けて、選択肢は３つあります。

- Sprockets を残す
    - 1) JavaScript だけ webpack に完全移行する (Rails推奨)
    - 2) JavaScript も Sprockets に残す (既存アセット活用したいニーズ)
- Sprockets を残さない
    - 3) webpack に完全移行、CSSに加え画像も


### Webpacker を使うか否か
なお、webpack を使う場合に Webpacker を使うかどうかも分かれます。

Rails の Webpacker は、Webpack をゴリゴリ使うときには外していくケースもあるようですが、まずは Webpacker でスタートして良さそうです（あとから外せるのであれば、あとでもよい）。

- webpacker 使う： 初期学習コストを下げる、あとで外す可能性あるのをよしとする
- webpacker 使わない： ある程度見通せている、自分で webpack できる

## 選択肢（１） Sprockets から webpack 完全移行
この場合は、既存のJavaScriptを webpack へ移行する必要があります。
既存資産活用の観点からは、取りづらい選択肢となります。

新たなアプリケーションを構築する場合、あるいはリファクタリングしながら、移行コストをかけても行う決定があれば、選択できると思います。

## 選択肢（２） Sprocketsを残して webpack を追加
既存のRailsアプリケーションにwebpackを追加する方法となります。
既存資産を活かす上では、もっともリーズナルブルな選択肢となります。

また、webpacker を利用することで、初期導入コストも低くなり、ほぼ無傷で導入が可能です。

ただし、webpacker で何をしたいのか？が明確でない場合、導入後にwebpack管理下に置くものと、Sprockets 管理下に置き続けるものが曖昧になります。
新しいものはwebpackにおいていくにしても、既存コードの修正や、既存コードを前提とした改修がSprockets側に行われるため、webpack側への移行が進まない可能性もあります。

### 単一ファイルコンポーネント(SFC, .vueファイル)
Vueの単一ファイルコンポーネント(SFC)では、 `.vue` の中でテンプレートやJavaScript、CSSを一緒に書くことができます。

Vue公式 単一ファイルコンポーネント
https://jp.vuejs.org/v2/guide/single-file-components.html

この `.vue` をJavaScriptやCSSに分離することを webpack は行なってくれます。 Sprockets は行なってくれません。
したがって、SFCはwebpackに置くことにすると、webpackを導入する意味が明確になります。

## 選択肢（３） Sprocketsを残さず webpack へ完全移行
ここでは既存資産を残す検討をしていたため、理解が進んだ早い段階で選択肢から外しました。


# ViewのVueと、SFCの違い
webpack で管理されたJavaScriptは、Deploy時にはbuildされています。Vue のSFCもそうです。

HamlなどのViewに、Rubyで Vue のJavaScriptを生成しているようなケースでは、Vue の SFC を使えません。 webpack による `.vue` のBuildは、リクエストごとには処理されないからです。

そのため、似たように Vue を用いる場合でも、View 内に動的な Vue を書くケースでは、 webpack ではなく 通常の JavaScript の読み込みとして Sprockets 管理下に Vue.jsをおきます。
たとえば gem `rails-vue` を引き続き利用する場合などです。

この場合、次の１行は残ったままとなります。

```
= javascript_include_tag 'application'
```

なお、動的生成ではない Vue は、素直に webpack へ移行が可能です。



# 参考情報
2018年 - 2019年くらいに書かれたものが多い。

## 融合について
RailsとVue.jsを融合する方法を採用した事例。

- Vue.jsとRailsの最適な融合を考える
    - https://tech.medpeer.co.jp/entry/2018/02/26/080000
- 実際のサービスをRails＋Vue.js(Single File Components)を用いてSPAへリファクタリングした話
    - http://techblog.housmart.co.jp/2018/08/06/vuejs-single-file-components-in-rails/
- SPAじゃないVue.js〜Railsとともに〜
    - https://qiita.com/yuyasat/items/b8203a134409b053f1f5

## 既存Rails と Vue SFC(単一コンポーネント) に webpack
既存のRailsアプリケーションにSFCを加えたい場合に参考になる。

- RailsでVue.jsのSFC（単一ファイルコンポーネント）を使うためにWebpackを入れてみた
    - https://tech.smartcamp.co.jp/entry/2019/05/16/201139

## webpack やら アセットパイプラインやらの理解
まずは理解することから必要な場合は、下記が関係性を説明していて分かりやすい。

Rails 6: Webpacker+Yarn+Sprocketsを十分理解してJavaScriptを書く: 前編（翻訳）

> 皆さんはアセットやJavaScript周りの変更で消耗してませんか？npm、Babel、ES6、Yarn、Webpack、Webpacker、Sprockets、これらのどこがどう違うのかさっぱりわからなかったりしますか？
>
> Rails 6アプリケーションでJavaScriptエコシステム全体がどのように機能しているかという概念を急いで理解する必要にかられているそこのお方、あなたが探しているのはまさにこの記事です。


## Webpack と SprocketにJavaScriptを並存する

Webpackを使っていても、Sprockets（既存のファイル）も使える。

> つまり、ビューで何かJavaScriptを使いたいとか使う必要に迫られたときは、これまでどおりSprocketsを使えるのです。
> - [Rails 6: Webpacker+Yarn+Sprocketsを十分理解してJavaScriptを書く: 後編（翻訳）](https://techracho.bpsinc.jp/hachi8833/2020_01_17/85943)

webpack でBuild、Sprockets管理下に配置という方法を取っているケースも。

> Webpack管理下のアセットをビルドした上で、生成物をRailsアプリケーションのSprockets管理下に配置します。
> - [RailsでVue.jsのSFC（単一ファイルコンポーネント）を使うためにWebpackを入れてみた](https://tech.smartcamp.co.jp/entry/2019/05/16/201139)

上記は webpacker を使わずに webpack導入しているが、webpacker で導入することもできる。