LoginSignup
5

More than 1 year has passed since last update.

Rails7でSvelteを使えるようにする

Last updated at Posted at 2022-08-09

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

さらに以下のファイルたちをプロジェクト直下に配置します。

svelte.config.js
import sveltePreprocess from 'svelte-preprocess'

export default {
  // Consult https://github.com/sveltejs/svelte-preprocess
  // for more information about preprocessors
  preprocess: sveltePreprocess()
}
tsconfig.node.json
{
  "compilerOptions": {
    "composite": true,
    "module": "ESNext",
    "moduleResolution": "Node"
  },
  "include": ["vite.config.ts"]
}
tsconfig.json
{
  "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に以下のようなファイルを作成。

BlogsShow.svelte
<script lang="ts">
</script>

<p>Hello Svelte</p>

そして、app/frontend/entrypoints/blogs-show.tsに以下のようなファイルを作成。

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の文字が!

image.png

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の表示によってタイトルと本文が二重に表示されている!

image.png

以上

以上でございます。
最初にも記載した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

これも誰か教えて下さい〜。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5