ViteJS, Rails, a wonderful combination
0. Motivation
We are building BootrAils on top of the last Rails version. When Rails 7 came out, it was (kind of) a relief to see a replacement for Webpacker. Whereas the new assets pipeline looks better, it seemed that room for even better could exist somewhere.
The current frontend assets management of Ruby-on-Rails could feel hacky for many developers :
- [live/auto/hot] reloading of HTML pages still doesnât work natively,
- Serving assets with Rails has changed multiples times, from nothing (Sprockets appeared with Rails 3.1), to not-completely-ready importmaps. Currently Rails support jsbundling, that wraps esbuild (or optionally another toolâŚ), before being injecting again to Sprockets. âimportmapsâ are optionally supported on top of this. And css bundling works another wayâŚ
What if you want a proper, unified, elegant, performant assets frontend management right from the start ?
Thereâs a gem for that
1. Prerequisites
Check that you have ruby 3 already installed. Check you also have bundler installed, and npm above version 7
1
2
3
4
5
6
7
8
$> ruby -v
ruby 3.1.0p0 // you need at least version 3 here
$> bundle -v
Bundler version 2.2.10
$> foreman -v
0.87.2
$> npm -v
7.1.0 // you need at least version 7.1 here
Any upper versions should work.
2. Create a new minimalistic Rails application
1
2
3
4
5
6
7
mkdir railsvite && cd railsvite
echo "source 'https://rubygems.org'" > Gemfile
echo "gem 'rails', '7.0.1'" >> Gemfile
bundle install
bundle exec rails new . --force --css=bootstrap --minimal
bin/rails db:create
bin/rails db:migrate
3. Install vite_rails
Open the Gemfile, and add
1
gem 'vite_rails'
Then in your terminal
1
2
bundle install
bundle exec vite install
4. What vite_rails installed into your Rails app
.gitignore was changed
1
2
3
4
5
6
7
# Vite Ruby
/public/vite
/public/vite-dev
/public/vite-test
node_modules
*.local
.DS_Store
Ok, not much surprises here. Vite.js is here to handle npm assets, so node_modules is safely ignored. Whatâs inside public/ is technically required by vite_rails, so far we donât have to know what it is about.
.Procfile.dev
Since Rails 7, you need foreman to start your local server with ./bin/dev
. This command actually calls foreman under the hood, looking for the local .Procfile.dev
vite_rails
overrides the default one as follow :
1
2
vite: bin/vite dev
web: bin/rails s
Ok, the frontend part runs separately from the server.
app/frontend/entrypoints/application.js
Wow ! Magic starts to happens right now. Instead of a separate directory for javascript, and other kind of assets, everything is now managed from app/frontend. That makes things a lot clearer. The content of this file is mostly docs, and a âhello worldâ from the console, so we wonât investigate it right now (but you can do it, for curiosity).
app/views/layouts/application.html.erb
The interesting part is here :
1
2
<%= vite_client_tag %>
<%= vite_javascript_tag 'application' %>
vite_client_tag : Renders the Vite client to enable Hot Module Reload, according to the docs.
vite_javascript_tag âapplicationâ : well, at first sight, this tag should include the javascript generated by vite.
So no more unclear javascript and stylesheet inclusion : now Vite rears everything for us.
package.json
1
2
3
4
5
6
{
"devDependencies": {
"vite": "^2.7.3",
"vite-plugin-ruby": "^3.0.4"
}
}
vite.config.ts
1
2
3
4
5
6
7
8
import { defineConfig } from 'vite'
import RubyPlugin from 'vite-plugin-ruby'
export default defineConfig({
plugins: [
RubyPlugin(),
],
})
What we can understand from vite.config.js is that we will profite from vite.js itself. So all docs from Vite.js are profitable for our project. See how nicely the RubyPlugin is included. It doesnât litter our configuration, and left all
Vite itself is included. Nothing hidden then, the vite-ruby-plugin is here to bridge the gap between Vite and the Rails application (tag helpersâŚ)
Other files changed
Less interesting, but worth mentioning : package-lock.json is changed (obviously), config/initializers/content_security_policy.rb
is also changed for security reasons, and bin/vite
is added to start vite itself when launching a local server.
4. End of the first-half â˝
Thatâs it ! Just by having a sneak peek at the code, everything seems elegant and intuitive from the start. Perfect ! đ
5. Create minimal files
Ok, so letâs test each of the expectations. First, we need the bare minimum files.
1
2
3
# inside app/controllers/home_controller.rb
class HomeController < ApplicationController
end
1
2
3
4
5
# inside config/routes.rb
Rails.application.routes.draw do
get "home/index"
root to: "home#index"
end
1
2
3
4
5
6
<!-- inside app/views/home/index.html.erb -->
<h1>This is h1 title</h1>
<button>
This is a button
</button>
These 3 files are enough to trigger a default view. Letâs try.
1
$/myapp> foreman start -f Procfile.dev
And open your browser
Great !
6. CSS with Vite and Rails
create file app/frontend/entrypoints/application.css
1
2
3
4
// inside app/frontend/entrypoints/application.css
h1 {
text-decoration: underline;
}
change app/views/layouts/application.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
<-- inside app/views/layouts/application.html.erb -->
<html>
<head>
<title>Myapp</title>
<%= vite_client_tag %>
<%= vite_javascript_tag 'application' %>
<!-- add line below, remove old stylesheet_link_tag -->
<%= vite_stylesheet_tag 'application' %>
</head>
<body>
<%= yield %>
</body>
</html>
Now stop your local server
Restart it :
1
$/myapp> foreman start -f Procfile.dev
And open your browser at localhost
Weâve just seen how Vite is able to handle stylesheets : just add an entrypoint in the well-named app/frontend/entrypoints folder, and reference it with the vite_stylesheet_tag helper in your layout.
7. Hot reloading with Rails and Vite
âHot reloadingâ means that the browser will automatically refresh itself, each time you change/save anything in your code editor.
For those who already used anything like React/Vue/whateverJSframework, it sounds already pretty obvious, because pressing âf5â into the browser each time is tedious when you have to write dozens of lines of code every day.
But believe it or not, it still doesnât apply to the default Rails app, even for the recent Rails 7 version.
Letâs try it, when Vite is installed.
Hot reloading CSS
Your localserver should be started. Comment and save the entire app/frontend/entrypoints/application.css file, and open your browser. The style of the title should have disappeared. Now uncomment and save the entire app/frontend/entrypoints/application.css file. The style of title should be underlined in your browser, automagically.
Hot reloading just works ! đđđ
Hot reloading JS
Try the same experience with app/frontend/entrypoints/application.js. You should see changes instantly happen in your browser.
Hot reloading HTML
If you try to change and save app/views/home/index.html.erb. What happened in your browser ? nothing. Uh-oh.
Itâs time to see how to add a plugin to ViteJS.
8. Add a plugin to ViteJS, with Rails
Hopefully for our HTML, ViteJs has a plugin dedicated to this task.
1
$/myapp> yarn add -D vite-plugin-full-reload
Quickly check the plugin was installed in package.json, then open vite.config.ts
1
2
3
4
5
6
7
8
9
10
11
// inside 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/**/*'], { delay: 200 })
],
})
Relaunch your local server. Try to change and save app/views/home/index.html.erb, now any change to the view automagically appears in your browser !
9. Credits
- ViteJS official website : https://vitejs.dev/
- vite_ruby documentation : https://vite-ruby.netlify.app/
- Vite and Rails integration, docs : https://vite-ruby.netlify.app/guide/rails.html
- vite_ruby GitHub repository : https://github.com/ElMassimo/vite_ruby
- vite_rails gem repository : https://github.com/ElMassimo/vite_ruby/tree/main/vite_rails
10. What a gem !
Itâs already a long tutorial, so thatâs it for today, but there will be more articles about the powerful Vite.
We have seen how ViteJS completely replaces the default Rails frontend assets management, in an intuitive manner.
Then weâve seen how hot reloading works, and how to add a Vite plugin to our application to achieve a nice development workflow.
Enjoy !