Vue3、Rails7系を使って「Hello Vue」を表示させるまで

Vue3、Rails7系を使って、何かアプリを作ってみたいなぁと思い、環境構築の段階で
学んだことを備忘録として残そうと思いました。


# 環境
ruby 3.1.0
Rails 7.0.4
vue@3.2.41
# railsの初期化

railsの初期化（アプリ作成）
```ruby
raiils new sample_app
```
# vueの初期化

**次にvueを導入していくが、いきなりつまりポイント**

railsの標準に搭載されているwebpackerでvueを導入していくつもりが・・・
``` ruby
rails webpacker:install:　vue
 => Don't know how to build task 'webpacker:install:vue' 
```

コマンドが使えない・・・
[曰く](https://github.com/rails/webpacker/issues/3052) rails7系 では、vueのインストールコマンドがなくなっているっぽい。

というか、[引退宣言](https://github.com/rails/webpacker#webpacker-has-been-retired-)がされており、そもそもRails7系では非推奨になっている...。

`webpacker`のコマンドを確認したところ、確かに`webpacker:install:vue`は存在しない。
なんてこった・・・
```ruby
 rails -T | grep webpacker
```



[Ruby on Rails 7, importmap and VueJS 3, no more webpacker](https://itnext.io/ruby-on-rails-7-importmaps-and-vuejs-3-no-more-webpacker-4ef06372a49c) を参考にさせていただいたところ`rails7系`では、`webpacker`ではなく、`importmap`という仕組みを使ってフロント側（`vue`、`javascript`とか）の実装を行えるそう。
[公式ドキュメント](https://ja.vuejs.org/guide/quick-start.html#%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88%E3%83%9E%E3%83%83%E3%83%97%E3%81%AE%E6%9C%89%E5%8A%B9%E5%8C%96)にも書かれている通り、インポートマップはインポートするファイルの場所をブラウザに教えることができるそう。

ただ、[ブラウザのバージョン規定](https://caniuse.com/import-maps)によるとインポートマップに対応しているブラウザも結構多い見たいです。そこで、
rails7系では、大多数のブラウザで使用されている [ES Module Shims](https://github.com/guybedford/es-module-shims#es-module-shims) を使用することで、ある程度のブラウザには対応できるようにしているそうです。
※ [IE には救いがないようだ・・・](https://caniuse.com/es6-module)

使い方は[Rails 7: importmap-rails gem README（翻訳）](https://techracho.bpsinc.jp/hachi8833/2022_06_29/112183)を参考にしながら進めていきます。

`Gemfile`に以下を追記して、`bundle:install`
```ruby
gem 'importmap-rails'
```

そうすると`config/importmap.rb`や`app/javascript/application.js.`などのファイルが生成されます。

# Vueのインストール方法
次にVueのインストールについてですが[公式ドキュメント ES モジュール ビルドの使用](https://ja.vuejs.org/guide/quick-start.html#cdn-%E3%81%AE-vue-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B)を参考にしながら進めていきました。


### ところで、ESモジュールってなに？

色々な記事を読むたびに出てくるESモジュールとはなんぞや。

以下の記事を参考に理解を深めていく
[JavaScriptでモジュールを使う時代](https://ics.media/entry/16511/)
[ES Modulesとは](https://zenn.dev/highgrenade/scraps/495a3a8775353e)

>ESモジュールとは、**「ES2015で策定されたJSファイルから別のJSファイルを読み込む仕組み」**
`ES2015`とは`JavaScript`の標準仕様のことで、いわゆるバージョンのこと。

>ブラウザの世界では、`JSファイル`を読み込むためには`script`タグを利用するが、
`ES Modules`が実装されている環境では、
・`import`文を利用することで、外部ファイルのJSファイルを読み込むことができる。
・外部ファイルの`JSファイル`では`export宣言`されたものが他の`JSファイル`から読み込まれる。

ほぇー
何気なしに使ってた`import文`について知れて感激


### インストール方法


Vue.js を使う場合、CDN を利用するのが一番簡単そうです (下記)。
```javascript
<script type="module">
  import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
</script>
```
しかし、ネットに繋がっていない場合や、サーバーが落ちた時に使用できなくなるデメリットが
あるのでローカルにインストールして、そこから読み込む方法をとりました。

以下`--download`コマンドで`vender/javascript`ディレクトリにダウンロードします。
```javascript
./bin/importmap pin "vue/dist/vue.esm-browser.js" --download
```

次に、先ほど生成した`config/importmap.rb`に以下を追記
ついでに`pin "application", preload: true`と
`pin_all_from "app/javascript/controllers", under: "controllers"`も追加します。


```importmap.rb
pin "application", preload: true # application.js を読み込みたい

pin "vue", to: "vue--dist--vue.esm-browser.js.js" # @3.2.41

# app/javascript/controllers 配下を読み込みたい
pin_all_from "app/javascript/controllers", under: "controllers" 
```
これで「`vender`フォルダにある`vue--dist--vue.esm-browser.js.js`ファイルを`vue`というパッケージ名として読み込む」という意味になり、`import Vue from "vue"`として書けるようになります。


次に`config/importmap.rb`を読み込めるように
`layout`ファイルに`javascript_importmap_tags`を追記します。
```eruby
<!DOCTYPE html>
<html>
  <head>
    <title>CodeSnippet</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>

　　　　　　　　<!--以下を追加-->
    <%= javascript_importmap_tags %>
    <!--controllers/application　配下を読み込む-->
    <%= javascript_import_module_tag 'controllers/application' %>
  </head>

  <body id="app">
    <%= yield %>
  </body>
</html>

```

### Hello Vue を表示させてみる

`routes.rb`に以下を追加
```routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
end
```

`app/controllers/home_controller.rb` に以下を追加
```home_controller.rb
class HomeController < ApplicationController
  def index; end
end
```

`view/home/index.html.erb` に以下を追加
```view/home/index.html.erb
<div>
  {{ text }}
</div>
```

`app/javascript/controllers/application.js` に以下を追加
```application.js

import * as Vue from "vue";

const App = Vue.createApp({
    data(){
        return {
            text: 'Hello Vue'
        }
    },
})

App.mount("#app");
```

では`rails s`でサーバーを立ち上げて`localhost:3000`にアクセスすると、以下の表示が見られます。DOM上に一瞬 `{{ text }}` が表示された後、`id="app"` にアタッチし、文字列を置き換えているのがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508607/f87f50a0-68df-decc-ac2a-c79ac0fc3915.png)


`importmap`が`head`内に展開され、`vue`がマッピングされた場所からインポートされていることが分かりました。`webpacker`だとアセットコンパイルによって`JS`ファイルを一つのファイルにギュッと圧縮してからブラウザに教えているところを、`importmap`では、`import`を使って、使用するファイルを一つずつブラウザに教えているようです。


# 結局 importmap で何が嬉しくなったのか
### JSのビルドがなくなる

例えば、**Webpackerを使用した場合**、複数の`JS`ファイルを1つの大きな`JS`にまとめているため、複数`JS`ファイルの内、1つでも変更があると、出来上がる大きな`JS`も変わってきます。つまり、**JSファイルをちょろっと変更しただけなのに、1から作り直すため時間が掛かってしまいました**。

一方、**importmapを使用した場合**、`JS`ファイルを個別で読み込んでいます。つまり、**変更のないファイルはキャッシュを利用し、変更のあったファイルだけ読み込むので、効率的**。

# importmapを導入して困りそうなこと

**・ブラウザのバージョンが低いと使用できない可能性がある。**
**・IEは100％使用できない**




# 最後に
こうして振り返るとそんなに難しいことはやっておらず、なんなら [Ruby on Rails 7, importmap and VueJS 3, no more webpacker](https://itnext.io/ruby-on-rails-7-importmaps-and-vuejs-3-no-more-webpacker-4ef06372a49c) に必要なことが全部書いてあるのも拘らず、変な回り道をして、それなりの時間がかかってしまいました。

ほんと、環境構築をサクッとこなしてしまう方々はすごいなぁと感じます。