#backend
Jul 27, 2022

Adding Vite to a Sprockets-Based Rails Application

Adrian Huna
Adrian Huna
Backendviterailsrubysprockets
Tai Bui
Adding Vite to a Sprockets-Based Rails Application

We gotta be honest. Even though at Showmax we are maintaining one platform for our customers and thus we pay significant attention to code quality, refactoring and staying up-to-date with the latest technologies, the frontend part of our full-stack applications built with the Ruby on Rails framework has been neglected. The main reason? Fear of the modern JavaScript world.

A couple of years back there was a meme about a new “best” JavaScript framework being released every month. The frontend tooling was evolving quickly, too, and while today we have great build tools such as rollupes_buildparcel and vite, when Rails 5.1 introduced webpacker (a way to use webpack easily in Rails apps), as mainly backend-focused engineers we really weren’t rushing to use it. As such, here we are – running Ruby on Rails 6 and 7 applications that still use sprockets as the way to bundle and build production assets.

With Rails 7, the default frontend approach has changed to import-maps but a traditional javascript bundling approach is available too. Most importantly, the webpacker project has been retired. Now that the scary webpacker is out of the way, it opens a new opportunity to start modernizing our frontend tooling.

Recently, Vite.js has emerged as a very popular next generation frontend tooling, and rightfully so. The Vite 3 announcement highlights the impact Vite has had on the current ecosystem, with the Laravel PHP framework using it by default and the vite-ruby gem also highlighted. In this article, we are going to look at how and why to take the first baby steps of introducing Vite into an application where the frontend is fully handled by sprockets.

The why

Let’s revisit the question of why we should even be introducing Vite into our applications.

  • For starters, it’s a modern frontend tooling and eventually we will be able to replace sprockets with it fully.
  • Second, thanks to the vite-ruby gem, it’s easy to integrate (as we will see in a moment).
  • Third, just by introducing vite-ruby into our application and updating a simple configuration file, we can immediately start enjoying a live reload of our server-side rendered application upon any file change.
  • Finally, Vite and sprockets can coexist without issues which opens up the opportunity of migrating our frontend to Vite in multiple phases.

Are you sold on the idea? Then let’s see how to do it.

The how

Integrating Vite into our Rails applications that use sprockets is very easy to do thanks to the vite-ruby gem. Before we start, let’s check the dependencies:

- Ruby 2.7
- Node.js ^14.18.0 || >=16.0.0

If your environment meets the minimum requirements, you shouldn’t run into any issues during Vite installation.

Let’s get to installing vite-ruby as the first step. Add vite_rails to your Gemfile:

gem 'vite_rails'

Then install the gem. Run in your terminal:

bundle install
bundle exec vite install

Vite-ruby automatically installed Vite into our application, congratulations! So what has changed? Let’s see by running git status.

modified:   .gitignore
  modified:   Gemfile
  modified:   Gemfile.lock
  new file:   Procfile.dev
  new file:   app/frontend/entrypoints/application.js
  new file:   bin/vite
  modified:   config/initializers/content_security_policy.rb
  new file:   config/vite.json
  new file:   package-lock.json
  new file:   package.json
  new file:   vite.config.ts

The interesting parts are the new app/frontend directory and the file application.js in it, which contains basic examples of how to work with ruby-vite. Also, the content_security_policy has changed to allow hot reloading of our files. But we don’t need to worry about that – baby steps, remember? The package.json file was created because our server-side rendered application really wasn’t using any npm packages up until now. Also, take note of the configuration files vite.config.ts and config/vite.json, as we will be working with them later.

If you are using .erb files, the vite-ruby tag helpers should be automatically injected into your application.html.erb file. We were using slim and the tags were not injected by default, so we needed to add them manually. Vite-ruby brings 3 new vite helpers: vite_javascript_tag, vite_typescript_tag, and vite_stylesheet_tag. These helpers enable you to create bundles that are parallel to your sprocket bundles so that you can migrate your frontend gradually.

In the why section, we put “live-reload” as one of the motivations for adding Vite to our application. In order to enable that we need to use another helper - vite_client_tag. In fact, we can just use this one helper to our application.html.slim file and forget about the others if we don’t want to start bundling javascript and css via Vite yet.

At this point, we are still not finished. While hot reloading is now working for the assets managed by Vite, we need to deal with live reload on change for sprockets assets as well as ruby files. Luckily Vite’s extensions ecosystem is rich and simple so we can just set up the vite-plugin-full-reload library to do the work for us.

In your terminal run:

npm i -D vite-plugin-full-reload

And as the README says, configure the plugin in the vite.config.ts file. The README recommends setting up reload on changes to config/routes.rb and app/views/**/*. For our use case, we decided to reload on any change to any file within the app folder:

FullReload(['config/routes.rb', 'app/**/*'], { delay: 100 }),

We can always adjust this setting if needed. Now that everything is ready, let’s run our server. We need to run 2 servers: the Vite server to enable the live reload and our standard rails server. In one terminal window run:

bin/vite dev

In a second terminal run:

bin/rails server

Open localhost:3000 and then enjoy the live reload every time you make a change in any of your application files!

Do you want to see how we take the next step? Reach out, we are hiring!

Share article via: