はじめに
Svelte というフロントエンドフレームワークはご存じでしょうか? 
Rails7からはTurboなどHotwireからJavaScriptを描かずともモダンなSPA風なページも作れるようにもなりましたね
個人的にフロントエンドフレームワークとしてReactは好きですし、他にもVue.jsなどは有名ですね!
そんなフロントエンドフレームワークの最近のトレンドを見てみると...
いろいろな分野で上位に来ている「Svelte」 
今回はこちらについて紹介とRailsと組み合わせてWebアプリを開発してみた記録を書かせていただきます
Svelte についての紹介
- 読み方は「すべると」 みたいです
 - コンパイラで仮想DOMは使用しない
- Reactなどは仮想DOMを使用している
 - ビルド時にアプリの変更箇所を探す
 
 
Svelteを使ってRailsアプリを開発してみる
Railsアプリを作成してフロントエンドをSvelteに設定してみましょう。
gemをインストールして作成する方法で試してみます。
調べみるといくつかgemは見つかりました
ただ、 svelte-railsについては 2020年ごろで開発が止まっていて2022年にアーカイブされている状態です。
試しにrails7で検証してみましたが、ビルドしてみると以下のようなエラーが起きるので上手くいきませんでした。
bundle exec rails svelte:install
rails aborted!
NameError: uninitialized constant Svelte::InstallGenerator::Webpacker (NameError)
      Webpacker.config.source_entry_path.relative_path_from(::Rails.root)
rails6等でビルドすれば上手くいくのかもしれないですが、アーカイブされているgemを今から使うのは色々リスクが伴うと思うので今から始めると言う人は vite_rails からviteを下地にsvelteを使ってみるのが良いと思います
今回諸々の検証バージョンは以下の通りです
$ ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-darwin20]
$ rails -v
Rails 7.0.8
$ bundle -v
Bundler version 2.4.18
基本的に上記READMEの手順をもとに進めていきます。Railsアプリを1から作るときデフォルトでJavaScriptのコードなどSvelteとの競合が起きる気がして面倒そうだったので --minimal オプションつけて最低限のRailsアプリの作成まで実行することに(javaScriptのみ要らなそうであれば -j とかでも良いかもです)
初期設定
参考) https://way-too-mainstream.vercel.app/articles/using-svelte-typescript-in-rails-7-vite-tutorial
$ rails new svelte-sandbox --minimal
$ cd svelte-sandbox
$ echo "gem 'vite_rails'" >> Gemfile
$ bundle install
$ bundle exec vite install
vite周りの設定
$ 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/**/*']),
  ],
})
svelteを追加
svelte のマウントするコードは一旦jsで作成しますが、ts対応させておきます
$ yarn add -D @sveltejs/vite-plugin-svelte @tsconfig/svelte svelte svelte-check svelte-preprocess tslib typescript
package.json に以下の行を追加
{
+  "type": "module",
  "devDependencies": {
...
以下のファイルをRails project rootに作成
import sveltePreprocess from 'svelte-preprocess'
export default {
  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": ".",
    "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/**/*']),
+    svelte(),
  ],
})
svelte を使う
topページを作成します
$ bin/rails generate controller tops index
svelte コンポーネント、マウントjsコードを追加
<script>
</script>
<p>Hello Svelte!!</p>
import TopsPage from '../components/TopsPage.svelte';
new TopsPage({
  target: document.getElementById('tops-page'),
});
#tops-page にマウントできるようになったため app/views/tops/index.html.erb にコンポーネント を描画するコードを追加します
<h1>Tops#index</h1>
<p>Find me in app/views/tops/index.html.erb</p>
+ <%= content_tag :div, '', id: 'tops-page' %>
+ <%= vite_javascript_tag 'tops-page' %>
動作確認
実際にサーバーを立ち上げてtops#index を確認してみましょう
$ bin/rails s
$ bin/vite dev
erb ファイルで書かれている pタグの下にsvelteコンポーネントが表示されていますね!
最後に
次の記事では svelteにデータを送信したり、細かい設定など変更していきたいと思います
