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
I built a version of the app, available online at https://hnpwa.onrails.blog and I open sourced the code at https://github.com/johnbeatty/hnpwa-app.
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.
The Data Design
All the data comes from the Hacker News firebase API, documented at: https://github.com/HackerNews/API. 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: https://speakerdeck.com/johnbeatty/yes-rails-does-support-pwas
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.
8 comments on “HNPWA With Rails + Stimulus.js”
[…] HNPWA With Rails + Stimulus.js […]
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
Thanks for letting me know. I fixed the bug, and the update is on Github.
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 ( https://github.com/FullHuman/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!
Best!
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
It’s managed inside a controller and some views.
The views, that use erb, are here:
https://github.com/johnbeatty/hnpwa-app/tree/master/app/views/service_worker
The controller that manages the views is here, but it currently doesn’t do much:
https://github.com/johnbeatty/hnpwa-app/blob/master/app/controllers/service_worker_controller.rb
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.
Thanks for the clarification, I had you really made setting up a PWA with rails simple
[…] HNPWA With Rails + Stimulus.js • Blogging On Rails on Stimulus + ActionCable + ActiveJob: Loading Asynchronous API Data […]