2024-06-23

rails に vite, TypeScript, React 導入

現在

importmaps にしている。ちゃんと bundle する形にしたい
importmaps だと React は jsx 使えないらしい(要出典)

参考

https://zenn.dev/salvage0707/scraps/1bd24c3293d85c

home#index 作る
エントリポイントが app/frontend/entrypoints/application.js これを front/entrypoints にしたい。vite_rails でできるはず
yarn create vite frontend --template react-ts を実行する。frontend directory ができるのだな
frontend/app/application.ts はなんなんだろうか?


https://www.mof-mof.co.jp/tech-blog/2024/04/22/124028

これは TypeScript + React

front#index を用意してその app/views/top/index.html.erb にマウントする形

vite_rails

gem 'vite_rails' # vite_rails_legacy if using Rails 4
$ bundle install
If you upgraded the gem manually, please run:
        bundle exec vite upgrade

# 一応やっておく
$ bundle exec vite upgrade
No such file or directory - npm

node 使える環境にしないといけない

.devcontainers/Dockerfile のほうにこれを追記

# Install Node.js and yarn
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y curl gnupg && \
    curl -sL https://deb.nodesource.com/setup_current.x | bash - && \
    apt-get install -y nodejs && \
    npm install --global yarn && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* /var/cache/apt/*

yarn のバージョンは 1.22.22

reinstall vite_rails

Gemfile から削除して
$ ./bin/bundle clean
$ ./bin/bundle
$ ./bin/bundle exec vite upgrade
Updating gems
Fetching gem metadata from https://rubygems.org/.........
Resolving dependencies...
Resolving dependencies...
Fetching minitest 5.24.0 (was 5.23.1)
Fetching rack 3.1.4 (was 3.1.3)
Fetching zeitwerk 2.6.16 (was 2.6.15)
Fetching irb 1.13.2 (was 1.13.1)
Installing zeitwerk 2.6.16 (was 2.6.15)
Installing minitest 5.24.0 (was 5.23.1)
Installing rack 3.1.4 (was 3.1.3)
Installing irb 1.13.2 (was 1.13.1)
Bundle updated!
1 installed gem you directly depend on is looking for funding.
  Run `bundle fund` for details
Upgrading npm packages # 今度はこけずに済んだぞ

added 31 packages in 8s

6 packages are looking for funding
  run `npm fund` for details
$ ./bin/bundle exec vite install
Creating binstub
Check that your vite.json configuration file is available in the load path:

        No such file or directory @ rb_sysopen - /workspaces/rails-playground/config/vite.json

Creating configuration files
Installing sample files
Installing js dependencies

added 1 package, and audited 33 packages in 962ms

6 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Adding files to .gitignore

Vite ⚡️ Ruby successfully installed! 🎉

bundle exec vite install で出来上がったファイルをみる

 ❯ git st
On branch introduce-vite_rails
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   .gitignore
	modified:   Gemfile
	modified:   Gemfile.lock
	modified:   Procfile.dev
	modified:   app/views/layouts/application.html.erb
	modified:   config/initializers/content_security_policy.rb

# ここら辺が新たにできたファイル
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	app/javascript/entrypoints/
	bin/vite
	config/vite.json
	package-lock.json
	package.json
	vite.config.ts

編集されているファイルを見る

diff --git a/Procfile.dev b/Procfile.dev
index da151fe..e6ad037 100644
--- a/Procfile.dev
+++ b/Procfile.dev
@@ -1,2 +1,3 @@
 web: bin/rails server
 css: bin/rails tailwindcss:watch
+vite: bin/vite dev


# app/javascript/entrypoints/application.js がエントリポイントになるのだな

diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 5374b55..366cfc6 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -16,6 +16,18 @@
     <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
     <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
     <%= javascript_importmap_tags %>
+    <%= vite_client_tag %>
+    <%= vite_javascript_tag 'application' %>
+    <!--
+      If using a TypeScript entrypoint file:
+        vite_typescript_tag 'application'
+
+      If using a .jsx or .tsx entrypoint, add the extension:
+        vite_javascript_tag 'application.jsx'
+
+      Visit the guide for more information: https://vite-ruby.netlify.app/guide/rails
+    -->
+
   </head>

   <body>

diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb
index b3076b3..aa21c5f 100644
--- a/config/initializers/content_security_policy.rb
+++ b/config/initializers/content_security_policy.rb
@@ -11,7 +11,16 @@
 #     policy.img_src     :self, :https, :data
 #     policy.object_src  :none
 #     policy.script_src  :self, :https
+    # Allow @vite/client to hot reload javascript changes in development
+#    policy.script_src *policy.script_src, :unsafe_eval, "http://#{ ViteRuby.config.host_with_port }" if Rails.env.development?
+
+    # You may need to enable this in production as well depending on your setup.
+#    policy.script_src *policy.script_src, :blob if Rails.env.test?
+
 #     policy.style_src   :self, :https
+    # Allow @vite/client to hot reload style changes in development
+#    policy.style_src *policy.style_src, :unsafe_inline if Rails.env.development?
+
 #     # Specify URI for violation reports
 #     # policy.report_uri "/csp-violation-report-endpoint"
 #   end

[54085 ms] Port forwarding 51341 > 45037 > 45037 stderr: Connection established
[55096 ms] rejected promise not handled within 1 second: Error: connect ECONNREFUSED 127.0.0.1:3000
stack trace: Error: connect ECONNREFUSED 127.0.0.1:3000
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1595:16)
[08:44:36] Error: connect ECONNREFUSED 127.0.0.1:3000
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1595:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 3000
}

うーん、上記は bin/setup で実行されているが、どうもうまく動いていないなあ?

bin/dev だと foreman で起動してくれるのだが

08:47:30 web.1  | * Listening on http://127.0.0.1:3000
08:47:30 web.1  | * Listening on http://[::1]:3000

vite も3036 で立ち上がる。auto forwarded らしい。つまり .devcontainer.json の forwardPorts で指定していなくても良さそう

08:53:18 vite.1 |   VITE v5.3.1  ready in 238 ms
08:53:18 vite.1 | 
08:53:18 vite.1 |   ➜  Local:   http://localhost:3036/vite-dev/
08:53:18 vite.1 |   ➜  press h + enter to show help
h
08:53:40 vite.1 | 
08:53:40 vite.1 |   Shortcuts
08:53:40 vite.1 |   press r + enter to restart the server
08:53:40 vite.1 |   press u + enter to show server url
08:53:40 vite.1 |   press o + enter to open in browser
08:53:40 vite.1 |   press c + enter to clear console
08:53:40 vite.1 |   press q + enter to quit

# oはダメっぽい
o
08:53:56 vite.1 | Error: spawn xdg-open ENOENT
08:53:56 vite.1 |     at ChildProcess._handle.onexit (node:internal/child_process:286:19)
08:53:56 vite.1 |     at onErrorNT (node:internal/child_process:484:16)
08:53:56 vite.1 |     at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

u
08:54:03 vite.1 | 
08:54:03 vite.1 |   ➜  Local:   http://localhost:3036/vite-dev/
# ずっとリロード状態になって何にも確認できん

/workspaces/rails-playground/app/javascript/entrypoints/application.js を編集してみる

ログで Rebuilding… となるので HMR は効いているようだ?

layout file を application とは別に articles というものを用意していたので、そこで vite_javascript_tag などを設定しないといけなかった

とりあえず application, articles 両方で同じエントリポイントを読み込んでいるが、別々のほうがよかったりするのかな?

application layout を使用する別のコントローラーを用意しても良いかも

importmaps と vite_rails の併用

turbo-rails, stimulus は importmaps で入れている。。。のであればそれはそれで良さそう

vite_rails は完全に front 側を管理するのに徹すればいけるかな?

以下のようなエラーが devtools console で出てしまう。しかし type="module" のスクリプトより先に読み込んでいるのだが…

An import map is added after module script load was triggered.

https://github.com/ElMassimo/vite_ruby/issues/417#issuecomment-1946414689

preload_links_header: false にしないといけないのかなあ


entrypoints を変更する

app/javascript/entrypoints/application.tsfront/entrypoints/application.ts に変更する

https://vite-ruby.netlify.app/config/index.html#sourcecodedir

sourceCodeDirfront に変更する。エントリポイントはそこからの相対である entrypointsDir front/entrypoints に変更される

tailwind の設定ではこうなっている。front 側の React component にも適用されるのだろうか?

'./app/javascript/**/*.js',

importmaps と vite_rails の併用というか共存というか

importmaps -> Turbo を使っている 使いたくないところでは javascript_importmap_tags を使わなければ良いのでは? 別のレイアウトファイルを作って検証する

app/controllers/front/articles_controller.rb

class Front::ApplicationController < ApplicationController
  layout 'front'
end
class Front::ArticlesController < Front::ApplicationController
  layout 'front'
  def index
  end
end

front layout では vite_typescript_tag を使う

Turbo が効いているページから遷移してきた時はどうなるんだろう