Rails7でSvelteを使う方法ってないのかな?と探していたんですが、全く見つからなかったので自分で試行錯誤した記録をここに記します。
やったことの軌跡がわかるようにPRを作ってありまして、基本このコミットの通りにやれば使えるようになるはず。
手順
rails newする
このとき、-J
や-j
オプションをつけて、javascript関連のファイルは生成されないようにしたほうが良いかもです。
後述しますが、vite_rails
を使用するので、生成されるjavascript関連のファイルが邪魔になるかもです。
自分は--minimal
をつけちゃいました。
'vite_rails'を追加する
Gemfileに以下を追記して、
gem 'vite_rails'
bundle install実行。
bundle install
さらに、初期化コマンドを実行。
bundle exec vite install
これでいろんなファイルが生成されます。
vite_railsについて
そもそもVite Rubyなるものがありまして、ViteとRubyをいい感じに統合してくれるツールです。
そしてその中で、rails用のvite_rails
というものがあるので、これをインストールしている感じです。
このviteを使用して、svelteを利用できるようにしていきます。
ホットリロードできるようにする
本筋からは外れますが、せっかくviteを入れたのだからホットリロードしてほしいっすよね。
package.jsonにvite-plugin-full-reload
を追加して、
{
"devDependencies": {
"vite": "^3.0.5",
- "vite-plugin-ruby": "^3.1.2"
+ "vite-plugin-ruby": "^3.1.2",
+ "vite-plugin-full-reload": "^1.0.3"
}
}
プラグインをインストールします。
yarn install
このままだとなぜかホットリロードしてくれないので、config/vite.jsonを以下のように修正します。
{
"all": {
"sourceCodeDir": "app/frontend",
"watchAdditionalPaths": []
},
"development": {
"autoBuild": true,
"publicOutputDir": "vite-dev",
- "port": 3036
+ "port": 3036,
+ "host": "127.0.0.1"
},
"test": {
"autoBuild": true,
"publicOutputDir": "vite-test",
"port": 3037
}
}
これでホットリロードがきくようになるので、起動中にerbファイルを直したら勝手にブラウザ上も表示が変更されるようになります。
ちなみにホットリロードさせるときは以下のコマンドでrailsを起動するようにします。
foreman start -f Procfile.dev
Procfile.dev
の中身を見ればわかりますが、bin/vite dev
もrailsサーバーと同時に起動しないといけないためです。
なので、事前にforemanのインストールは必要ですね。
svelteを追加する
package.jsonを以下のように修正します。
{
+ "type": "module",
"devDependencies": {
"vite": "^3.0.5",
"vite-plugin-ruby": "^3.1.2",
- "vite-plugin-full-reload": "^1.0.3"
+ "vite-plugin-full-reload": "^1.0.3",
+ "@sveltejs/vite-plugin-svelte": "^1.0.1",
+ "@tsconfig/svelte": "^3.0.0",
+ "svelte": "^3.49.0",
+ "svelte-check": "^2.8.0",
+ "svelte-preprocess": "^4.10.7",
+ "tslib": "^2.4.0",
+ "typescript": "^4.6.4"
}
}
そしてインストール実行。
yarn install
さらに以下のファイルたちをプロジェクト直下に配置します。
import sveltePreprocess from 'svelte-preprocess'
export default {
// Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors
preprocess: sveltePreprocess()
}
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node"
},
"include": ["vite.config.ts"]
}
{
"extends": "@tsconfig/svelte/tsconfig.json",
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"resolveJsonModule": true,
"baseUrl": ".",
/**
* Typecheck JS in `.svelte` and `.js` files by default.
* Disable checkJs if you'd like to use dynamic types in JS.
* Note that setting allowJs false does not prevent the use
* of JS in `.svelte` files.
*/
"allowJs": true,
"checkJs": true,
"isolatedModules": true
},
"include": ["./**/*.d.ts", "./**/*.ts", "./**/*.svelte"],
"exclude": ["./public/**/*", "svelte.config.js",],
"references": [{ "path": "./tsconfig.node.json" }]
}
そして、vite.config.tsを以下のように修正。
import { defineConfig } from "vite";
import RubyPlugin from "vite-plugin-ruby";
import FullReload from "vite-plugin-full-reload";
+import { svelte } from "@sveltejs/vite-plugin-svelte";
export default defineConfig({
plugins: [RubyPlugin(), FullReload(["config/routes.rb", "app/views/**/*"])],
plugins: [
RubyPlugin(),
FullReload(["config/routes.rb", "app/views/**/*"]),
+ svelte(),
],
});
これでSvelteを使う準備ができました。
※ここらへんのファイルたちは、yarn create vite
をしてsvelteプロジェクトを生成したときに作られたファイルたちをコピってきてるだけです。
常に最新で試したい場合には、自らsvelteプロジェクトを生成して、作られたファイルを自分でコピってきたほうがいいです。
Svelteを使ってみる
とりあえずscaffold
bin/rails g scaffold Blog title:string article:string
とりあえず、/blogs/1
とかにアクセスが来たらsvelteコンポーネントを表示できるようにしていきます。
tsファイルとsvelteファイルを追加
まず、app/frontend/components/BlogsShow.svelte
に以下のようなファイルを作成。
<script lang="ts">
</script>
<p>Hello Svelte</p>
そして、app/frontend/entrypoints/blogs-show.ts
に以下のようなファイルを作成。
import BlogsShow from "../components/BlogsShow.svelte";
new BlogsShow({
target: document.getElementById("blogs-show"),
});
erbからentrypointsのtsファイルを参照する
vite_railsでは、erbファイルにvite_typescript_tag
を用いると、app/frontend/entrypoints
配下にあるtsファイルを参照できるようになります。
例えば以下のように書けば、
<%= vite_typescript_tag 'blogs-show' %>
app/frontend/entrypoints/blogs-show.ts`ファイルを参照することができるようになるということです。
ということで、実際にやってみます。
app/views/blogs/show.html.erb
を以下のように修正します。
<p style="color: green"><%= notice %></p>
+<%= content_tag :div, "", id: "blogs-show" %>
+<%= vite_typescript_tag 'blogs-show' %>
<%= render @blog %>
...
以下のようにrailsを起動して、
foreman start -f Procfile.dev
http://127.0.0.1:5100/blogs にアクセス。
適当に記事を作って http://127.0.0.1:5100/blogs/1 とかにアクセスすると、Hello Svelte
の文字が!
propsを渡す
svelteコンポーネントにpropsを渡したいときには、dataにわたすようにします。
<%= content_tag :div, "", id: "blogs-show" %>
<%= content_tag :div, "", id: "blogs-show", data: {title: @blog.title, article: @blog.article}%>
で、entrypointsのtsファイル側で、svelteをnewするときにpropsを渡します。
+const target = document.getElementById("blogs-show");
+
new BlogsShow({
- target: document.getElementById("blogs-show"),
+ target: target,
+ props: {
+ blog: {
+ title: target.dataset["title"],
+ article: target.dataset["article"],
+ },
+ },
...
svelte側では普通にpropsを受け取る形で書けばOKです。
<script lang="ts">
+ export let blog: {
+ title: string;
+ article: string;
+ };
</script>
-<p>Hello Svelte</p>
+<h1>{blog.title}</h1>
+<p>{blog.article}</p>
http://127.0.0.1:5100/blogs/1 とかを見ると、svelteとerbの表示によってタイトルと本文が二重に表示されている!
以上
以上でございます。
最初にも記載したPRの内容をなぞって書いているだけなので、もし動かなかったりしたら、動いた実績のあるPR見たほうが早いかもです。
ちなみに
自分はいつもjavaとreactばっか使ってるんですが、railsでreactやsvelte使うときってどうやって使うもんなんですか?
・railsプロジェクトには入れるけど、reactやsvelteはSPAとして作って、rails側はAPIとして動かし、erbファイルは1つくらいしか作らない
なのか
・あくまでMVCの形は崩さず、個々のerbからreactやsvelteを参照させるようにして、erbでビューは開発、ちょっと動きつけたいところにreactやsvelteを使う
なのか
・MVCの形は崩さず、個々のerbからreactやsvelteを参照させるようにするが、erbはdiv一個だけとかにして、ビューの実装は主にreactやsvelteで行うようにする
なのか。
誰かおしえてください〜。
ほか
久しぶりにrails触るモチベとして、型のある開発に興味があったのですが、2022/08/10時点でrails7でやろうとすると無理っぽいですよね?
VSCodeまっかっかになってわけわからなくなりました。
↓にrails関連の型定義がバージョン7で作られたらできるようになるのかな?
https://github.com/ruby/gem_rbs_collection/tree/main/gems
これも誰か教えて下さい〜。