Getting Started with Vite on Rails

Getting Started with Vite on Rails

A few months ago, we were working on a Rails 7 app using Webpack 5. One of the main problems we had was that making a small change in the Javascript took around 39 seconds to recompile. You can imagine how much productivity we lost just waiting, and honestly, I personally remember getting really distracted during that dead time, just sitting there.

At that point, Webpacker had been retired opens a new window , so we checked the official migration guide opens a new window and found several options: the first was jsbundling-rails opens a new window , the second was Shakapacker opens a new window , another was Importmaps opens a new window , and finally, we knew we had the option to try Vite opens a new window .

We finally went with Vite, which (as noted on GitHub) is named after the French word for “quick” (pronounced /vit/, like “veet”). Our reload time improved a lot, it dropped to just one second, which felt like magic. In this post, I’ll explain why we chose it, and also why we got such a huge speed improvement.

What is Vite and why use it

Vite opens a new window is a modern frontend build tool created by Evan You (the same creator of Vue.js). Its main goal is to make development fast. Really fast.

The key difference with older tools like Webpack is how it handles your code during development. Instead of bundling everything before serving the app, Vite serves your files directly using native ES modules. This means your browser loads only what it needs, instantly.

Native ES modules: Modern browsers can load Javascript files using the import and export syntax directly, without needing a bundler. This allows tools like Vite to serve files faster and more efficiently during development. Learn more on MDN. opens a new window

When you change a file, Vite uses something called Hot Module Replacement (HMR) — it updates only that part of the app in the browser, without reloading everything. That’s why reloads feel almost instant.

Hot Module Replacement (HMR): Under the hood, HMR works by sending updates over a WebSocket connection from the Vite development server to the browser. Only the changed Javascript modules are replaced in the running app, without a full reload. This preserves application state and provides near-instant feedback for changes to components, styles, or logic. Read more in the Vite docs. opens a new window

Here are some of the main reasons why developers love Vite:

  • It starts up super fast, so you’re not left waiting to see your changes.
  • Vite is built on modern tools like ESBuild opens a new window and Rollup opens a new window .
  • Hot Module Replacement (HMR) gives you live updates while you code, as mentioned above.
  • The configuration is simple and much less complex than Webpack.
  • It’s framework agnostic, so you can use it with React, Vue, Svelte, or plain JavaScript.
  • When you build for production, Vite uses Rollup to create optimized bundles.

In short, Vite focuses on speed and simplicity, which makes it a perfect match for Rails developers who don’t want to spend hours fighting with frontend tooling.

Why We Finally Chose Vite

We have a really big app, around 11 years of Javascript code that has grown quite complex. With about 30 engineers deploying regularly, we needed a migration path that could be gradual. Vite made that possible, since it allows multiple entry points. That meant we could migrate one part of the app at a time, without breaking everything.

On the other hand, we had a very old Webpack configuration, even some custom code and monkey patches (small hacks to change library behavior) that nobody fully remembered why they existed. When we tried a quick proof of concept by using Shakapacker opens a new window , we realized it was going to be much more complicated than we expected, especially because of all that legacy code.

We also tried another POC with jsbundling-rails opens a new window . It was our second option, our plan B. We were already familiar with it, and we even had some internal experience from when we wrote this post about migrating from Webpacker to ESBuild opens a new window . But in our specific context, it was not easy to get it working smoothly. The structure of our Javascript and the amount of legacy code made it difficult to get good results.

Finally, as soon as we tested the most basic Vite entry point, it worked perfectly. It took us less than one morning to get it running, and from that moment, we had no doubts. Vite was the way to go.

Setup example:

Let’s see how to install Vite in a Rails app. In this example, we’ll start from a Rails 7 project, but it also works for Rails 8.

First, let’s add the gem:

bundle add vite_rails

Then run the installer:

bundle exec vite install

This command will create a few files:

vite.config.ts
app/frontend/
app/views/layouts/vite.html.erb

Now you can start the development server. You need to run two commands in two different terminals:

bin/rails server
bin/vite dev

The first one is the classic one, and the second one runs the Vite dev server, which is going to handle your Javascript, CSS, and other frontend files.

If you prefer to run both servers with a single command, you can use Foreman opens a new window and a Procfile.dev. For example:

web: bin/rails server
vite: bin/vite dev

Then start both processes together with:

foreman start -f Procfile.dev

After that, open your Rails layout and make sure you are using the Vite helpers instead of the old asset helpers. For example:

<%= vite_client_tag %>
<%= vite_javascript_tag 'application' %>
<%= vite_stylesheet_tag 'application' %>

Example: Vite Entrypoint File

The entrypoint is the main JavaScript file that Vite uses to start your application. It’s where you import your app’s modules and kick off any logic you want to run on page load. By default, vite_rails looks for entrypoints in app/frontend/entrypoints/.

Here’s a simple example of what your main entrypoint file (e.g., app/frontend/entrypoints/application.js) might look like:

// app/frontend/entrypoints/application.js
import './greetings.js';

console.log('Vite is working!');

And in greetings.js:

// app/frontend/entrypoints/greetings.js
export function greet(name) {
	console.log(`Hello, ${name}!`);
}

greet('Rails developer');

This setup will ensure your code is loaded as an entrypoint by Vite, and you’ll see the output in your browser’s console when you reload the page.

That’s it. Now every time you change a JavaScript file, you’ll see the update almost instantly in the browser.

Compatibility

vite_ruby opens a new window and vite_rails opens a new window are compatible with the following Ruby and Rails versions:

Rails Version Ruby Version Supported
8.x >= 2.5 Yes
7.x >= 2.5 Yes
6.x >= 2.5 Partial*
5.1–5.2 >= 2.5 Partial*
< 5.1 < 2.5 No

*Partial: Some features may not work or be documented for Rails 6.x and below.

Make sure you are using Rails 7 or newer for the best experience.

Moving Forward

If you want a faster, smoother frontend workflow in your Rails app, Vite is a great option to check out. It’s quick to set up and can really speed up your development, especially if you’ve dealt with slow reloads or complicated old configs before.

Give it a shot in a side project or a feature branch and see how it works for you.

Get the book