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/inertia @inertiajs/inertia-svelte @inertiajs/progress
Enter fullscreen mode Exit fullscreen mode

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

import axios from 'axios'

import { createInertiaApp } from '@inertiajs/inertia-svelte'
import { InertiaProgress } from '@inertiajs/progress'

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

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

InertiaProgress.init()

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({
      experimental: {
        prebundleSvelteLibraries: true
      }
    })
  ]
})


Enter fullscreen mode Exit fullscreen mode

This config file does two things: 1. It ensures that you only have one copy of axios in your bundle. 2. It enables an experimental feature to work around a current bug in Vite.

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/inertia-svelte'
import { InertiaProgress } from '@inertiajs/progress'

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

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

InertiaProgress.init()

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 😊

Discussion (5)

Collapse
danielrlc profile image
Daniel Clarke • Edited on

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 Author

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

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
astorrer profile image
Aaron Storrer • Edited on

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