vite_railsで複数のエントリーポイントをビルドする

vite_railsで複数のエントリーポイントをビルドする

Tech
Rails
作成: 2025年2月24日 更新: 2025年5月7日

以下のようにjsやcssをなんらかの単位で分けてビルドしたい場合、railsの通常のビルドの設定ではなくvite_railsを使うと便利。

entrypointsにはvite_railsでビルドするターゲットファイルを設置。ターゲットファイルから他のディレクトリにある資材を読み込むことになる。

frontend
  |-- entrypoints < buildの対象を配置
  |-- main < エンドユーザー向けの資材
  |-- admin < 管理画面用の資材
  |-- lp < 広告配信用の資材

vite_railsのインストール

まず、デフォルトのビルド設定を省きたいので、--skip-javascriptを設定してrails newする。

$ rails new . --skip-javascript

自分の場合、他にも取り除きたいものがあったので、こんな感じで実行。それぞれ必要になったら、後から足せばOK

rails new . --skip-action-mailbox --skip-javascript --skip-jbuilder --skip-brakeman --skip-rubocop --skip-ci --skip-kamal --skip-test --skip-system-test --skip-thruster

そしたらvite_railsをインストール。そしてviteの設定ファイルを生成。

$ bundle add vite_rails
$ bundle exec vite install

そうすると、config/vite.jsonvite.config.tspackage.jsonができる。ビルド関連で必要なものや設定があればさらにここへ追加すればOK。

{
  "all": {
    "sourceCodeDir": "app/frontend",
    "watchAdditionalPaths": []
  },
  "development": {
    "autoBuild": true,
    "publicOutputDir": "vite-dev",
    "port": 3036
  },
  "test": {
    "autoBuild": true,
    "publicOutputDir": "vite-test",
    "port": 3037
  }
}
import { defineConfig } from 'vite'
import RubyPlugin from 'vite-plugin-ruby'

export default defineConfig({
  plugins: [
    RubyPlugin(),
  ],
})
{
  "private": true,
  "type": "module",
  "devDependencies": {
    "vite": "^5.4.14",
    "vite-plugin-ruby": "^5.1.1"
  }
}

npm installをしてnodeのモジュールをインストールしておく

$ npm install

このままbin/devをしてもrailsのサーバーのみが立ち上がるだけで、viteのホットリロードなどが動作しない。

そこで、foremanを使ってbin/devを実行したときにrailsサーバーとviteが同時に立ち上がるように変えていく。

$ bundle add foreman --group development # これは開発環境のみインストールされていればOK

foremanが読み込むProcfile.devはすでにviteとrailsが同時に走るようになっているので、そのままでOK

vite: bin/vite dev
web: bin/rails s

bin/devの中身をforemanを実行するように変更。これでbin/devを実行すると、http://localhost:5100でrailsの最初の画面が表示され、背後でviteも動いているようになる。

# 変更前
#!/usr/bin/env ruby
exec "./bin/rails", "server", *ARGV

# 変更後
#!/usr/bin/env sh
bundle exec foreman start -f Procfile.dev

ただ、5100のポートって普段からrails使っている人だとちょっと慣れない。

おなじみの3000を使いたいときは、以下のような感じでProcfile.devのrailsのところを書き換えてあげると3000で起動するようになる。

vite: bin/vite dev
web: unset PORT && bin/rails s

資材の配置

あとは、最初に書いた構成でapp/frontend配下にディレクトリを作り、jsとかcss、画像を配置すればviteが自動でbuildをしてくれる。

ただ、画像についてはfrontend直下のimagesしかデフォルトでは読み込んでくれない。それぞれのエントリーポイントごとに画像も別で管理したい場合は以下のようにconfig/vite.jsonで読み込み対象として追加してあげる。

{
  "all": {
    "sourceCodeDir": "app/frontend",
    "watchAdditionalPaths": [],
    "additionalEntrypoints": [
      "~/main/images/**/*",
      "~/admin/images/**/*",
      "~/lp/images/**/*"
    ]
  },
  "development": {
    "autoBuild": true,
    "publicOutputDir": "vite-dev",
    "port": 3036
  },
  "test": {
    "autoBuild": true,
    "publicOutputDir": "vite-test",
    "port": 3037
  }
}

あとは、layouts/application.html.erbあたりでapp/frontend/entrypointsに配置した資材を読み込むように指定してあげればOK。

おそらくこの構成取りたい場合はlayoutsもそれぞれentrypointsごとに用意することになると思うので、適宜作成しておきましょう。

<!DOCTYPE html>
<html>
  <head>
    <title><%= content_for(:title) || "Nice project" %></title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="mobile-web-app-capable" content="yes">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= yield :head %>

    <link rel="icon" href="/icon.png" type="image/png">
    <link rel="icon" href="/icon.svg" type="image/svg+xml">
    <link rel="apple-touch-icon" href="/icon.png">

    <!-- 以下3点を追加 -->
    <%= vite_stylesheet_tag 'main.css' %>
    <%= vite_client_tag %>
    <%= vite_javascript_tag 'main' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

画像を読み込むときは以下のような感じでvite用のヘルパーを使用する。

他にも資材の読み込み方については、こちらに詳細があります。

<%= vite_image_tag 'main/images/cat.png' %>

HotwireとStimulusを有効にする

rails newしたときに--skip-javascriptをしたので、HotwireとStimulusが入っていません。

改めてセットアップするにはturbo-railsとstimulus-railsのgemをインストールして、セットアップコマンドを実行

$ bundle add turbo-rails stimulus-rails
$ bin/rails turbo:install
$ bin/rails stimulus:install

インストールは完了するんだけど、残念なことにyarnでインストールされてしない、yarn.lockができてしまった。

もともとyarnを使うつもりなら問題ないけど、npmを使いたい場合は一旦yarn.lockを削除して、npm installを実行しておこう

$ rm yarn.lock
$ npm install

そして、Turbo(Hotwire)とStimulusをインストールしたときに、デフォルトのテンプレートがapp/javascriptに作られているのだけどviteを使う場合app/frontendに資材を配置しないといけない。

紛らわしいので、一旦app/javascriptは削除してstimulus-vite-helpersのインストールしておく。stimulus-vite-helpersはvite上でstimulusのcontrollerを効率よく読み込むためのヘルパーを提供してくれる。

$ rm -rf app/javascript
$ npm install stimulus-vite-helpers

エントリーポイントの対象となるファイルに以下のような設定をしてあげればOK。

あとは/main/js/controllers/配下にいつものようにStimulusのコードを配置しておけばvite上で稼働します。

import "@hotwired/turbo-rails"
import { Application } from '@hotwired/stimulus'
import { registerControllers } from 'stimulus-vite-helpers'

const application = Application.start()
const controllers = import.meta.glob('../main/js/controllers/*_controller.js', { eager: true })
registerControllers(application, controllers)

ある程度規模の大きいサイトやサービスになると、複数の想定ユーザーごとにフロントエンドが必要になるケースはよくありうると思う。

そうしたときに、vite_railsを使うと綺麗に分けやすいですよ、という話でした。Sassも使えるようになります。

バージョン情報

  • rails 8.0.1
  • vite_rails 3.0.19