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:
- ✅ Faster initial load times → Essential for first-time visitors.
- ✅ Better Lighthouse and Core Web Vitals scores → Affects SEO ranking.
- ✅ Reduced bandwidth usage → Important for mobile users.
1. Asset Compression in Rails 8
Rails 8 uses Importmaps and Propshaft for asset management. To reduce asset sizes:
- Kamal 2 Deployments (Thruster + Puma): Asset compression and delivery are automatically handled by the web server.
- Ensure Precompressed Assets: Kamal 2 typically runs asset compilation within the Dockerfile or deploy configuration, so manual execution is unnecessary.
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>
- Lazy load images only when they enter the viewport.
- Preload video metadata, not the full file, reducing bandwidth use.
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.