RailsからWebpackerを剥がして、Vite RubyでVue3 + TypeScriptを導入する
はじめに
Vite は Vue.js 開発者の Evan You 氏によって開発されたフロントエンドのビルドツールです。
Vue.js はもちろん、React や Svelte もサポートされています。
既存の Rails プロジェクトに Vue.js3 と TypeScript を導入するにあたって、Rails 自体の脱 Webpacker 化の流れもあり、代替を検討していたところ、Vite が候補に上がりました。
ちょうどVite Rubyというライブラリが良さげだったので、試してみることにしました。
前提
- Webpacker を使用している Rails6 プロジェクト
- Rails を API サーバー専用とするのではなく、Rails の view 内に Vue コンポーネントを埋め込む
- APIサーバーにするのがメジャーだとは思いますが、いきなりこの方式にするのは影響が大きすぎるので、まずは部分的に導入していくことを想定しています
- Rails6 + Vue.js3 + TypeScript
- 複数エントリーポイントを持つ
手順
事前準備:Webpacker導入済のRailsプロジェクトを用意する
-
ディレクトリ作成・bundler初期化
mkdir Vue3-TypeScript-with-Vite-Rails cd Vue3-TypeScript-with-Vite-Rails bundle init
-
Gemfile書き換え
gem 'rails', '~> 6.1.0' # 追加
-
Railsプロジェクト作成
bundle install bundle exec rails _6.1.0_ new . -d mysql --skip-test # Gemfileを上書きするか聞かれるので、Yを入力
-
Webpackerインストール
rails install:webpacker
-
database.ymlを設定して
rails db:create
を実行設定例
# MySQL. Versions 5.5.8 and up are supported. # # Install the MySQL driver # gem install mysql2 # # Ensure the MySQL gem is defined in your Gemfile # gem 'mysql2' # # And be sure to use new-style password hashing: # https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html # default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password socket: /tmp/mysql.sock development: <<: *default database: vue_with_webpack_development # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: <<: *default database: vue_with_webpack_test # As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password or a full connection URL as an environment # variable when you boot the app. For example: # # DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase" # # If the connection URL is provided in the special DATABASE_URL environment # variable, Rails will automatically merge its configuration values on top of # the values provided in this file. Alternatively, you can specify a connection # URL environment variable explicitly: # # production: # url: <%= ENV['MY_APP_DATABASE_URL'] %> # # Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full overview on how database connection configuration can be specified. # production: <<: *default database: vue_with_webpack_production username: vue_with_webpack password: <%= ENV['VUE_WITH_WEBPACK_DATABASE_PASSWORD'] %>
Vite Ruby導入
-
vite_rails
インストール-
Gemfileに下記追加
gem 'vite_rails'
-
下記を実行
bundle install bundle exec vite install
-
bundle exec vite install
コマンドにより下記を実行してくれます-
bin/vite
を作成 -
vite
,vite-plugin-ruby
のパッケージをインストール - 設定ファイル(
vite.config.ts
,config/vite.json
)を追加 - サンプルのエントリーポイントを作成
- Webpacker導入済(app下にjavascriptディレクトリがある場合)
- エントリーポイントは
app/javascript/entrypoint/application.js
- エントリーポイントは
- 上記以外の場合
- エントリーポイントは
app/frontend/entrypoint/application.js
- エントリーポイントは
- Webpacker導入済(app下にjavascriptディレクトリがある場合)
- application.html.erb に上記エントリーポイントのヘルパータグを挿入
-
-
-
-
Full Reload設定
-
viewが変更された際にホットリロードする設定を行います。
yarn add -D vite-plugin-full-reload
// vite.config.ts import { defineConfig } from "vite"; import RubyPlugin from "vite-plugin-ruby"; // これを追加 import FullReload from "vite-plugin-full-reload"; export default defineConfig({ plugins: [ RubyPlugin(), // これを追加 FullReload(["config/routes.rb", "app/views/**/*"], { delay: 100 }), ], });
-
-
bin/vite dev
でサーバーを起動できればOK
Vue.js3, TypeScript導入
-
参考
-
Vue.js3, TypeScript関連のパッケージと、ViteのVue.js用プラグインをインストール
yarn add -D @vitejs/plugin-vue @vue/compiler-sfc typescript vue@next
-
vite.config.jsにVue.jsプラグインの設定を追加
import { defineConfig } from "vite"; import RubyPlugin from "vite-plugin-ruby"; import FullReload from "vite-plugin-full-reload"; // これを追加 import vue from "@vitejs/plugin-vue"; export default defineConfig({ plugins: [ RubyPlugin(), FullReload(["config/routes.rb", "app/views/**/*"], { delay: 100 }), // これを追加 vue(), ], });
-
tsconfig.jsonを追加する
{ "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "sourceMap": true, "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], "skipLibCheck": true, "allowSyntheticDefaultImports": true }, "include": ["**/*.ts", "**/*.d.ts", "**/*.tsx", "**/*.vue"], "exclude": [ "node_modules" ] }
-
Vueコンポーネントを作成
<!-- app/javascript/components/Test.vue --> <template> <p>{{ state.message }}</p> </template> <script lang="ts"> import { defineComponent } from "vue"; export default defineComponent({ name: "Test", setup() { return { state: { message: "Hello Vue3 + TypeScript!", }, }; }, }); </script> <style scoped> p { font-size: 2em; text-align: center; } </style>
-
エントリーポイントを作成して、コンポーネントをマウント
- Webpackerで
app/javascript/packs
以下に既にエントリーポイントを作成している場合は、app/javascript/entrypoints
以下に移動します。- このとき、必ずentrypoints直下にjs or tsファイルを配置してください。
- entrypoints以下のディレクトリ構成がネストされていても、バンドルの出力先ではそのネスト構造が保持されず、一律でpublic/vite/assets(developの場合はpublic/vite-dev/assets)直下に出力されます。
- そのため、ネスト構造でファイル名に重複がある場合、viewから正しく呼び出せません。この問題を回避するため、entrypoints直下に一意のファイル名となるよう配置しましょう。
- このとき、必ずentrypoints直下にjs or tsファイルを配置してください。
// app/javascript/entrypoints/test.ts import { createApp } from "vue"; import Test from "../components/Test.vue"; document.addEventListener("DOMContentLoaded", () => { createApp(Test).mount("#test"); });
- Webpackerで
-
エントリーポイントをviewで呼び出し
- 今回は複数エントリーポイントを持つ前提としているので、使用したいVueコンポーネントを表示するerbファイル内で呼び出しています
- 単一エントリーポイントの場合は、app/view/layouts/application.html.erbで呼び出します。
<%= vite_client_tag %> <%= vite_javascript_tag 'test' %> <div id="test"></div>
-
サーバーを起動し、コンポーネントが表示されていればOKです。
bin/vite dev & rails s
参考
今回使用したリポジトリです。
記事内容よりも作業を進めて、APIをコンポーネントを実装して簡易的なつぶやきリストを作っています。
https://github.com/shu-illy/Vue3-TypeScript-with-Vite-Rails
なお、コンポーネントのUIに関しては、Vue.js3の学習に使ったこちらのUdemy講座から流用させて頂いています。
https://www.udemy.com/course/vue3-typescript/
最後に
最初はWebpackerを剥がしてWebpackでVue.js3とTypeScriptを導入しようとしていました。
が、フロントエンド経験が浅い僕にとってはwebpack.config.js周りの設定が煩雑でかなりハマってしまいました。
そこでViteを使うことにしたのですが、Vite Rubyのおかげで驚くほどあっさり導入できました。
Webpackerのように設定ファイルを抽象化されているわけでもないですし、Webpackerほど諸々の依存関係をRailsに支配されているわけでもなさそう(?)なので、ひとまずRailsでViteを使う時にはVite Rubyでいいのではないかと思っています。
参考になれば幸いです。
Discussion