DEV Community

Stefan Buhrmester
Stefan Buhrmester

Posted on • Updated on

Setting up a new Rails 7 app with Vite, Inertia, and Svelte

Rails 7 has been released and Webpacker is being phased out.

And if you're anything like me and prefer to use HMR and component frameworks over Hotwire and importmaps, you might want to look for a Webpacker alternative now. I found Vite Ruby to be a capable replacement, which also (supposedly) makes your development flow more fasterβ„’.

So let's take a look at how to set up a new Rails 7 app using my favorite frameworks out there (Inertia and Svelte) and bundle it all up with Vite.

Let's go

Start off by initializing a new Rails 7 app without Javascript and asset pipeline:

rails new app --skip-javascript --skip-asset-pipeline
Enter fullscreen mode Exit fullscreen mode

Once this is done, add the inertia_rails and vite_rails gems:

bundle add inertia_rails
bundle add vite_rails
Enter fullscreen mode Exit fullscreen mode

The vite_rails gem adds an installer to your project. Run it with

bundle exec vite install
Enter fullscreen mode Exit fullscreen mode

This generates default vite config files, a frontend directory, and also updates your layout file to include the vite bundle. It will also setup our initial package.json. We'll need more packages. Add them:

npm install -D axios svelte @sveltejs/vite-plugin-svelte @inertiajs/svelte
Enter fullscreen mode Exit fullscreen mode

IMPORTANT UPDATE:
Since vite-plugin-svelte version 2.0, it is required that your package.json contains "type": "module". You will have to add this manually if it doesn't already.

Then find application.js in our new app/frontend/entrypoints directory and replace its contents with:

import axios from 'axios'

import { createInertiaApp } from '@inertiajs/svelte'


const pages = import.meta.glob('../pages/**/*.svelte')

const csrfToken = document.querySelector('meta[name=csrf-token]').content
axios.defaults.headers.common['X-CSRF-Token'] = csrfToken



createInertiaApp({ 
  resolve: name => pages[`../pages/${name}.svelte`](),
  setup({ el, App, props }) {
    new App({ target: el, props })
  },
})

Enter fullscreen mode Exit fullscreen mode

Next, open up your vite.config.ts file and change it like so:

import { defineConfig } from 'vite'
import RubyPlugin from 'vite-plugin-ruby'
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default defineConfig({
  resolve: {
    dedupe: ['axios']
  },
  plugins: [
    RubyPlugin(),
    svelte()
  ]
})


Enter fullscreen mode Exit fullscreen mode

This config file ensures that axios is only included once in your bundle, and Inertia and your own imports will actually resolve to the same axios.

Now you can place your Inertia page components into app/frontend/pages, start your rails server with rails s, the dev server with ./bin/vite dev, and it should all work as usual.

Bonus: Persistent Layouts

In the example above you might have noticed the lack of a persistent layout - a parent component that won't change upon navigation. To add a persistent layout, update your application.js like this:

import axios from 'axios'

import Layout from '../pages/_layout.svelte'

import { createInertiaApp } from '@inertiajs/svelte'

const pages = import.meta.glob('../pages/**/*.svelte')

const csrfToken = document.querySelector('meta[name=csrf-token]').content
axios.defaults.headers.common['X-CSRF-Token'] = csrfToken

createInertiaApp({ 
  resolve: async name => {
    const page = await pages[`../pages/${name}.svelte`]()
    return Object.assign({layout: Layout}, page)
  },
  setup({ el, App, props }) {
    new App({ target: el, props })
  },
})

Enter fullscreen mode Exit fullscreen mode

Now you can use persistent layouts with Inertia and Vite.

Happy coding 😊

Top comments (9)

Collapse
 
danielrlc profile image
Daniel Clarke • Edited

Thanks – great article! For anyone else new to Rails like me who gets stuck rendering their first Svelte view after following the article here, create/edit these files:

# config/routes.rb
Rails.application.routes.draw do
  root 'home#index'
end

# app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
    render inertia: 'home/index'
  end
end

<!-- app/frontend/pages/home/index.svelte -->
<h1>Home page</h1>
Enter fullscreen mode Exit fullscreen mode

(Feedback appreciated. I don't know if this is the standard "Rails way" or not.)

Collapse
 
buhrmi profile image
Stefan Buhrmester

The component file names are case-sensitive. Try render inertia: 'home'

Collapse
 
peterbell215 profile image
peterbell215

This is an excellent article that I used as the starting project for my side project. I found I needed to tweak the vite.config.ts file:

export default defineConfig({
  plugins: [
    RubyPlugin(),
    FullReload(["config/routes.rb", "app/views/**/*"]),
    svelte(),
  ]})

Enter fullscreen mode Exit fullscreen mode
Collapse
 
buhrmi profile image
Stefan Buhrmester

that's a nice tip, thanks

Collapse
 
boriscy profile image
Boris Barroso

Thanks for posting this, I will start a new project and this setup is great

Collapse
 
asmorris profile image
Andrew

Awesome article! Just used this to get an app up and running in ~10 mins, love using this stack honestly.

Collapse
 
chmich profile image
Christian Sedlmair • Edited

Thanks, great article.
Had trouble how to access variables from Server, what i missed: i had to export the variable from the javascript, so the code is:

Controller (see: inertia docs)

 def index
    render inertia: 'svelte/index', props: { backend_var: 'Backend' }
 end
Enter fullscreen mode Exit fullscreen mode

Svelte (see: svelte docs)

<svelte:head>
    <title>Hello {backend_var}</title>
</svelte:head>
<script>
    export let backend_var
</script>

Enter fullscreen mode Exit fullscreen mode
Collapse
 
chmich profile image
Christian Sedlmair • Edited

I had to combine the old ujs and i'm using Hotwired on Vite. Here's how i integreated it all together: Setup Vite, Svelte, Inertia, Stimulus, Bootstrap / Foundation on Rails-7. On the parts Svelte and Inertia it references back to this Tutorial.

Collapse
 
astorrer profile image
Aaron Storrer • Edited

I visited your browser-based game link. LOL, very creative name. XD