💭 where are you taking me?

rails

⚡♦️ Fixing module preload paths with a Rails/Vite Setup

Hello and happy new year! Today I'm writing about an asset related issue in a Rails application. Enjoy!

Several months ago, I migrated my Rails app from Webpack(er) to Vite, and I’ve been quite happy with the switch. Vite is blazingly fast, well-documented, and works seamlessly once properly configured.

This morning, while resolving CSP violations (all fixed now, by the way 🎉), I encountered the following error in the browser’s developer console:

Failed to load module script: Expected a JavaScript-or-Wasm module script but the server responded with a MIME type of “text/html”. Strict MIME type checking is enforced for module scripts per HTML spec.

(This message comes from Chromium; it may appear slightly differently in other browsers.)

TL;DR

Stick around for the full story:

Nothing on my site appeared broken, but I wanted to resolve the issue anyway so I put on my debugging glasses.

My first findings in order:

  1. The problem doesn’t occur on every page load
  2. In the network tab, I noticed that certain requests were failing (highlighted in red)
  3. The trigger was the import of chart library modules
  4. The response content type of the failing requests was text/html, even though a JS file was requested
  5. The issue occurred only on specific servers (visible as i have a header showing the server name)

Given these observations, it became clear that the issue was tied to my asset host configuration. In short, I have one server that serves assets via a subdomain and also functions as a regular app server.

But why did the site still work despite failing imports?

A bit of research revealed that Vite preloads modules by default (see MDN on modulepreload). In a nutshell, JavaScript modules are preloaded for performance gains (they are not actually used until explicitly imported in your JS).

Since this behavior is controlled via an HTML attribute, I checked my page source and found several modulepreload links. These used relative paths, meaning they pointed to myapp.com/assets/foo.js instead of assets.myapp.com/assets/foo.js. As a result, requests hit the application servers, which responded with HTML instead of the JS file.

So why was Vite generating links with relative paths?

After some digging, I found a related issue. The fix is to set Rails.application.config.action_controller.asset_host (see the Vite Ruby docs).

Once configured, Vite generates absolute paths in the preload tags, resolving the issue.

However, I noticed URLs with double leading slashes (e.g., //assets.myapp.com/...). To fix this, I adjusted the Vite config:

import { defineConfig } from "vite"
import RubyPlugin from "vite-plugin-ruby"

export default defineConfig({
  base: "./",
  // other build configuration omitted
})

TL;DR

Adapt the following two things (first one is mandatory) to fix the issue:

# config/application.rb
# Can be set via environment variable
config.action_controller.asset_host = "https://yourassethost.yourapp.com" 
// vite.config.mts
export default defineConfig({
  base: "./",
  // other build configuration omitted
})

I needed to fix some specs and could deploy to staging for acceptance 😌

I hope this helps you if you run into a similar issue. Enjoy your day, and stay curious!

#rails #vite #viteruby #webdev

As the title suggests, this is a short technical post.

I spent too much time today trying to figure out how to fix my GitLab pipeline after upgrading the Ruby version in a Rails app from 3.4.2 to 3.4.5.

The problem

I have two jobs that connect to the MySQL 8.4 database service: one for testing migrations and one for the RSpec test suite. Both jobs failed quickly with the following error message:

ERROR 2026 (HY000): TLS/SSL error: self-signed certificate in certificate chain
bin/rails aborted!
failed to execute: `mysql`

The solution

I'm still not sure what the root cause of the issue is, but I think it's related to the Ruby Docker images I use. I've switched from ruby:3.4.2-slim to ruby:3.4.5-slim. I realized that I have to disable SSL certificate verification within the MariaDB client, so i added the following to my Dockerfile:

RUN echo "[client] \ndisable-ssl-verify-server-cert" >> ~/.my.cnf

And voilà, my jobs are running like a charm again!

I hope this is helpful for you. Please bear in mind that disabling the SSL connection is usually undesirable in production environments. Have a good day and happy debugging!

#ruby #ruby345 #rails8 #mysql2gem #debugging #rails