Skip to content

Blogging On Rails

Everything on Rails!

HNPWA With Rails + Stimulus.js

Sometimes you want a development side project that will push you. A project that is non trivial, and provides lots of opportunities to think through problems as you build a complicated, data hungry application.

The Hacker News Progressive Web App is one such specification for building interactive websites that mirror Hacker News. It’s marketed as the spiritual successor to the TodoMVC project specification, and its goal is to provide an opportunity for developers to experiment solving the same problem in many different ways. But it focuses on front end javascript frameworks, leading one to think: ”Which percentage of webpages have such a front end complexity, that you need to write more than some Javascript sprinkles?”

I wondered if I could build a web app against the HNPWA spec that rivaled the performance and interactivity of any front end framework, but using basic Ruby on Rails libraries and that only needed Javascript sprinkled throughout the app. After all, Progressive Web Apps are really a constellation of conventions. Those conventions fit neatly into Rails, without the need to introduce a complicated Javascript front end. By embracing core Rails technologies like ActiveJob, ActionCable, Russian Doll Caching, and sprinkles of Stimulus, you can deliver powerful and immersive front end web apps.

HNPWA using Rails + Stimulus

Screenshot of the main page
Screenshot of the main page

I built a version of the app, available online at and I open sourced the code at

This version of the Hacker News Progressive Web app is built on top of Rails. It uses ActionCable for out of band communication between the front end and the back end. It uses ActiveJob to load in the Hacker News API in the background. It uses Russian Doll Caching everywhere to reuse rendered HTML. Stimulus.js provides the front end functionality wherever it’s needed. This app, as deployed in production, performed very well on the Google Lighthouse Audit and markets test, while fulfilling all the specs of the HNPWA.

Google Lighthouse Audit from production
Google Lighthouse Audit from production
Emerging Markets 3g connection test
Emerging Markets 3g connection test

The Data Design

All the data comes from the Hacker News firebase API, documented at: There are two models, an Item and and a User. The Item can be any of the stories, or it can be comments related to the stories. There is also implicit metadata associated with any item: where it belongs on a page. A story could be on the Top page and the Job page, or the New page and the Show page, or perhaps any of the five pages at the same time. This implicit design was made explicit by building a metadata class that kept track of an item’s location in one of the 5 public lists.

There are 5 different metadata models, each of which keeps track of the item’s location in it’s associated list. The TopItem keeps track of locations and caching for an Item in the /top list, The NewItem keeps track of locations and caching for an Item in the /new list, and so on for the other three models.

An ActiveJob for each of the categories loads all the item ids in order in from the API, and then spawns new jobs to load in the individual items. The results are rendered into HTML, cached, and sent over ActionCable to anyone who is listening. Stimulus is responsible for setting up the ActionCable channels on the front end, and listening for changes to items and for changes to locations, like in this tutorial.

More lessons coming soon

I plan on extracting a number of lessons out of building this web app, and how they can apply to building interactive and immersive web apps. One theme is talked about at RailsConf was about not blocking the perceived ”main thread“. Our customers expect some lag on loading pages, but with a little work on our part, apps can feel as fast as native apps.

Comments or Questions? Let me know how your experience went below.

Want To Learn More?

Try out some more of my Stimulus.js Tutorials.

RailsConf Slides

I gave a talk about this app at RailsConf 2019. Slides are available here:

I’ll add the video of the talk when it’s available. Thank you to everyone who came up and said hello at RailsConf. I appreciate your support, and it’s great to hear from you all.

Looking to make your Rails app more interactive?

Subscribe below, and you won’t miss the next Rails tutorial, that will teach you how to make really interactive web apps that just work.

We won’t send you spam. Unsubscribe at any time.

8 comments on “HNPWA With Rails + Stimulus.js”

  1. While visiting the site I get:

    A bad HTTP response code (500) was received when fetching the script.
    new:1 Uncaught (in promise) TypeError: Failed to register a ServiceWorker: A bad HTTP response code (500) was received when fetching the script

  2. Thank you very much for sharing this. This is super useful information. One thing you could also do to improve Remove unused CSS and Eliminate render-blocking resources from Google Lighthouse:

    1. Use PurgeCSS ( in order to remove unused CSS by adding the config settings inside postcss.config.js. This will save 24kb from the entire CSS file.

    2. For Eliminate render-blocking resources, you could preload the CSS / JS file with tag or HTTP2 Early Hints.

    I can’t wait to put into practice what I learned on your post and also looking forward for the RailsConf video 🙂

    Have a wonderful day!

  3. Hi, I’ve taken a look at the repo and I’ve noticed that you removed erb loaders from Webpack config, I was wondering how do you handle generate the asset paths for the manifest.json

    1. It’s managed inside a controller and some views.

      The views, that use erb, are here:

      The controller that manages the views is here, but it currently doesn’t do much:

      This works well, mitigating the need for a lot of extra configuration, and it gets to use the asset_path helpers. It works with webpacker and the asset pipeline.

Leave a Reply

Your email address will not be published. Required fields are marked *