Optimizing Rails Assets for PWA Performance

Why Asset Optimization is Crucial for PWAs

Performance is a core requirement of Progressive Web Apps. Google’s Core Web Vitals emphasize fast loading times, smooth interactions, and visual stability, all of which are affected by asset sizes and loading strategies.

Optimizing assets in a Rails PWA means:


1. Asset Compression in Rails 8

Rails 8 uses Importmaps and Propshaft for asset management. To reduce asset sizes:

Enable Gzip or Brotli Compression

If you’re using Nginx, enable Brotli compression:

brotli on;
brotli_static on;
brotli_types text/plain text/css application/javascript application/json;
gzip on;
gzip_types text/plain text/css application/javascript application/json;

2. Optimizing JavaScript Delivery

For Importmaps

Importmaps allow the browser to fetch only the required modules dynamically. Ensure you pin only necessary modules in config/importmap.rb:

pin "application", preload: true
pin_all_from "app/javascript/controllers"

This reduces JavaScript load time by preventing unnecessary script downloads.

For esbuild

Modify config/environments/production.rb:

config.assets.js_compressor = :esbuild
config.assets.css_compressor = :sass

If using Webpack, add:

NODE_ENV=production bin/webpack

This strips unnecessary spaces, comments, and unused code.


3. Lazy Loading Images and Videos

For images, use lazy loading to improve rendering speed:

<img class="lazy-load" data-src="<%= image_path('real-image.jpg') %>" alt="Lazy Loaded Image">
<script>
  document.addEventListener("DOMContentLoaded", function () {
    const images = document.querySelectorAll("img.lazy-load");

    const observer = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const img = entry.target;
          img.src = img.dataset.src;
          img.classList.remove("lazy-load");
          observer.unobserve(img);
        }
      });
    });

    images.forEach(img => observer.observe(img));
  });
</script>

For videos:

<video controls preload="metadata">
  <source src="video.mp4" type="video/mp4">
</video>

4. Using Service Worker Caching for Assets

Modify your service worker to cache static assets efficiently:

const CACHE_NAME = 'pwa-assets-v1';

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      return cache.addAll([
        '/offline.html',
        '/stylesheets/application.css',
        '/javascripts/application.js'
      ]);
    })
  );
});

This allows assets to load instantly after the first visit, even offline.


By implementing these optimizations, you ensure that your Rails 8 PWA delivers a fast and smooth experience, improving both SEO and user engagement.