Andy from Webcrunch

Subscribe for email updates:

Portrait of Andy Leverenz
Andy Leverenz

January 28, 2024

Last updated January 30, 2024

How to Add Live Reload to Your Rails Application

Live reload is an incredible tool for developers looking to boost their productivity. In this tutorial, I will walk you through implementing live reload in your Ruby on Rails application using esbuild.

Implementing live reload can significantly streamline your development workflow, saving you valuable time and effort. You can instantly see the results by automatically refreshing your app whenever you make changes without manually reloading the page.

To achieve this, we will leverage the power of esbuild, a cutting-edge technology for fast and efficient JavaScript bundling. By combining esbuild with Ruby on Rails, we can create a seamless live reload experience that will streamline your development process.


Table of Contents

  1. Introduction
  2. Setting Up Your Rails Project
  3. Installing Necessary Gems and Dependencies
  4. Configuring Esbuild
  5. Creating the Live Reload Script
  6. Putting It All Together
  7. Live reload alternatives for Ruby on Rails
  8. Conclusion
  9. Continue learning

Introduction

Live Reload automates the refresh process of your web page whenever you make changes to your code. This feature not only saves time but also enhances your overall development experience.

Setting Up Your Rails Project

Start by creating a new Rails project with Tailwind CSS and esbuild:

rails new livereload -c tailwind -j esbuild

Installing Necessary Gems and Dependencies

First, ensure you have the jsbundling-rails gem installed. If not, add it to your Gemfile and run bundle install.

Next, set up esbuild with Rails:

./bin/bundle exec rails javascript:install:esbuild

Add the chokidar package for file watching:

yarn add chokidar -D

Configuring esbuild

Create and customize an esbuild.config.js file in your project:

// esbuild.config.js
const esbuild = require("esbuild")
const chokidar = require("chokidar")
const http = require("http")
const path = require("path")

const isProduction = process.env.RAILS_ENV === "production"
const watchMode =
  process.argv.includes("--watch") || process.argv.includes("--reload")
const reloadMode = process.argv.includes("--reload")
const port = 5678

// Esbuild configuration
const esbuildConfig = {
  entryPoints: [path.join("app/javascript", "application.js")],
  bundle: true,
  minify: isProduction,
  sourcemap: !isProduction,
  outdir: path.join("app/assets/builds"),
}

// Start the esbuild build process
esbuild.build(esbuildConfig).catch(() => process.exit(1))

// Set up a simple HTTP server for live reload with CORS headers
const clients = []
const server = http.createServer((req, res) => {
  // Set CORS headers
  res.setHeader("Access-Control-Allow-Origin", "*")
  res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS")
  res.setHeader("Access-Control-Allow-Headers", "Content-Type")

  res.writeHead(200, {
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache",
    Connection: "keep-alive",
  })

  clients.push(res)

  req.on("close", () => {
    clients.splice(clients.indexOf(res), 1)
  })
})

server.listen(5678)

// Watch for file changes 
chokidar
  .watch([
    "app/javascript/**/*",
    "app/views/**/*",
    "app/assets/stylesheets/**/*",
  ])
  .on("all", () => {
    esbuild.build(esbuildConfig)
    clients.forEach((client) => client.write("data: reload\n\n"))
  })

console.log("Live reload server running on http://localhost:5678")

This configuration sets up esbuild and a simple HTTP server for the live reload functionality.

Here's a simplified explanation of what the code in esbuild.config.js is doing, hopefully, broken down into more straightforward terms:

  1. Setting Up Tools and Checking the Environment:
    • The code starts by loading some necessary tools: esbuild, chokidar, and http. esbuild helps in bundling and optimizing JavaScript files, chokidar watches for file changes, and http is used to create a server.
    • It checks if the Rails app is in production mode. This helps the code decide whether to optimize files for faster performance or not.
  2. Configuring Esbuild:
    • A configuration is set for esbuild. This includes where to find the JavaScript files, whether to bundle them together and where to save them. It's like giving esbuild a map and a to-do list.
  3. Starting the Build Process:
    • esbuild starts its job using the configuration provided. If something goes wrong, it stops the process to avoid more issues.
  4. Creating a Mini Server for Live Reload:
    • The code sets up a small server. This server's job is to send messages to the web browser to refresh the page whenever there are changes.
    • It makes sure that any browser is allowed to connect to this server (that's what CORS headers do).
  5. Listening for Changes:
    • chokidar starts watching files in your JavaScript, views, and stylesheets directories. Whenever there's a change in these files, it tells esbuild to rebuild them.
    • After rebuilding, it notifies all connected browsers to refresh the page. This means you see the changes in your web app immediately ✨.
  6. Running the Server:
    • Finally, the server starts, and the code tells you that it's running and ready to reload your pages automatically on http://localhost:5678.

Creating the Live Reload Script

Now, add a live_reload.js file to app/javascript and import it in application.js:

// app/javascript/live_reload.js

if (process.env.NODE_ENV === "development") {
  const source = new EventSource("http://localhost:5678")
  source.onmessage = (event) => {
    if (event.data === "reload") {
      window.location.reload()
    }
  }
}

Update the package.json script

// package.json
"scripts": {
    "build:css": "tailwindcss --postcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css --minify",
    "build": "node esbuild.config.js"
  },

This script listens for the "reload" event cast from our esbuild configuration and refreshes the page. We created a new EventSource for the server created by the build configuration.

Putting It All Together

With these configurations, your Rails app is now set up for live reloading. You can start your Rails server and begin coding. The browser automatically reloads whenever you change your JavaScript, stylesheets, or views. This ultimately saves you time and sanity during development.

Live reload Alternatives for Ruby on Rails

If you’re looking for alternatives to the esbuild-driven method I introduced in this tutorial, there are plenty of other options with Rails. Some options depend on specific technologies or front-end frameworks but accomplish similar goals.

  1. Guard LiveReload
    • Description: Guard LiveReload automatically refreshes your browser when 'view' files are modified.
    • Link: Guard LiveReload on GitHub
  2. Rack::LiveReload
    • Description: A Rack middleware that inserts the LiveReload script into your app's responses. Works well with apps not using Webpacker.
    • Link: Rack::LiveReload on GitHub
  3. Webpacker
    • Description: Though primarily for managing JavaScript, Webpacker can be configured for hot module replacement, similar to live reloading.
    • Link: Webpacker on GitHub
  4. BrowserSync
    • Description: Not specific to Rails, BrowserSync can synchronize file changes and interactions across multiple devices, ideal for responsive testing.
    • Link: BrowserSync
  5. React Hot Loader
    • Description: React Hot Loader enables hot module replacement for a smoother development experience if you use React with Rails.
    • Link: React Hot Loader on GitHub
  6. Vite Ruby
    • Description: Vite Ruby integrates Vite.js with Ruby on Rails, offering a fast front-end build tool with features like hot module replacement.
    • Link: Vite Ruby on GitHub

Conclusion

Live Reload is an awesome tool for enhancing your Rails development workflow. It reduces the time spent on manual refreshes, allowing you to focus more on development. The result is more efficient coding and better development of apps.

Continue learning

Link this article
Est. reading time: 7 minutes
Stats: 2,439 views

Categories

Collection

Part of the Ruby on Rails collection