Templatus (Hotwire edition)
Templatus is an opinionated template to build web applications with Ruby on Rails and Hotwire. It simplifies the process of setting up a new application while following best practices.
Live demo available at https://templatus-hotwire.ledermann.dev
There is a sister repository that uses Vue.js instead of Hotwire: https://github.com/ledermann/templatus/
Features / Technology stack
Backend
- Ruby 3.1
- Ruby on Rails 7.0
- ActionCable for WebSocket communication
- PostgreSQL for using as SQL database
- Sidekiq for background processing
- Redis for Caching, ActionCable, and Sidekiq
Frontend
- Hotwire for building the frontend without using much JavaScript by sending HTML instead of JSON over the wire
- ViewComponent for creating reusable, testable & encapsulated view components
- Slim for writing templates instead of ERB
- Tailwind CSS 3 to not have to write CSS at all
- Heroicons for beautiful hand-crafted SVG icons
- esbuild for bundling JavaScript
Development
- Puma-dev for using .test-domain and HTTPS in development
- Foreman for starting up the application locally
- dotenv to load environment variables from .env into ENV
- Prettier for auto-formatting JavaScript and Ruby code in Visual Studio Code
- Lookbook as development UI for ViewComponent
- Live reloading
Linting and testing
- RuboCop for Ruby static code analysis
- ESLint for JavaScript static code analysis
- RSpec for Ruby testing
- Factory Bot for setting up Ruby objects as test data
- Cypress for E2E testing
Deployment
- Docker for production deployment, NOT for development
- DockerRailsBase for fast building an optimized Docker image based on Alpine Linux
- GitHub Actions for testing, linting, and building Docker image
- Dependabot configuration for updating dependencies (with auto-merge)
- Ready for serving assets via CDN like CloudFront
- Honeybadger for error tracking in Ruby and JavaScript
- Lockup to place a staging server behind a basic codeword
Production
- Lograge for single-line logging
- Gzip and Brotli compression of all responses (HTML, JSON, assets) using Rack::Deflater, Rack::Brotli and Sprockets::ExportersPack
- Fine-tuned Content Security Policy (CSP)
- Ready for PWA (manifest, service-worker)
Metrics
This template is developed with optimized performance and security in mind. The following benchmarks are performed against the demo installation on production. It uses an inexpensive virtual server on the Hetzner Cloud behind a Traefik setup.
Lighthouse site performance
100% in all categories.
Security headers
What's the red Permissions-Policy badge? This seems to be fixed with one of the next Rails update: rails/rails#41994
Mozilla Observatory
WebPageTest
GTmetrix
Check-your-website
JavaScript size
133 KB of compiled JavaScript (minified, uncompressed). The largest parts are:
- Turbo with ActionCable (72 KB)
- Stimulus (32 KB)
- Honeybadger (22 KB)
$ yarn build
yarn run v1.22.18
$ node esbuild.config.js
../assets/builds/application.js 133.4kb 100.0%
├ ../../node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js 62.3kb 46.7%
├ ../../node_modules/@hotwired/stimulus/dist/stimulus.js 31.8kb 23.8%
├ ../../node_modules/@honeybadger-io/js/dist/browser/honeybadger.js 21.2kb 15.9%
├ ../../node_modules/@rails/actioncable/src/connection.js 2.8kb 2.1%
├ ../../node_modules/@rails/actioncable/src/connection_monitor.js 2.3kb 1.7%
├ ../../node_modules/register-service-worker/index.js 1.7kb 1.3%
├ ../../node_modules/@rails/actioncable/src/subscriptions.js 1.2kb 0.9%
├ ../../node_modules/@rails/actioncable/src/subscription_guarantor.js 864b 0.6%
├ ../../node_modules/el-transition/index.js 805b 0.6%
├ ../../node_modules/timeago.js/esm/utils/date.js 668b 0.5%
├ ../../node_modules/@rails/actioncable/src/consumer.js 583b 0.4%
├ controllers/online_status_controller.js 568b 0.4%
├ ../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/cable_stream_source_element.js 522b 0.4%
├ utils/setupServiceWorker.js 519b 0.4%
├ ../../node_modules/@rails/actioncable/src/index.js 499b 0.4%
├ ../components/clicks/component_controller.js 480b 0.4%
├ ../../node_modules/timeago.js/esm/realtime.js 409b 0.3%
├ ../../node_modules/@rails/actioncable/src/subscription.js 400b 0.3%
├ ../../node_modules/@rails/actioncable/src/internal.js 365b 0.3%
├ ../../node_modules/@hotwired/turbo-rails/app/javascript/turbo/cable.js 256b 0.2%
├ ../../node_modules/timeago.js/esm/lang/zh_CN.js 220b 0.2%
├ ../../node_modules/timeago.js/esm/lang/en_US.js 197b 0.1%
├ ../../node_modules/timeago.js/esm/utils/dom.js 158b 0.1%
├ utils/setupHoneyBadger.js 157b 0.1%
├ rails:/Users/ledermann/Projects/templatus-hotwire/app/javascript/controllers/**/*_controller.js 151b 0.1%
├ ../../node_modules/@rails/actioncable/src/logger.js 107b 0.1%
├ controllers/timeago_controller.js 104b 0.1%
├ rails:/Users/ledermann/Projects/templatus-hotwire/app/components/**/*_controller.js 96b 0.1%
├ utils/metaContent.js 92b 0.1%
├ utils/setupStimulus.js 77b 0.1%
├ ../../node_modules/timeago.js/esm/register.js 75b 0.1%
├ ../components/index.js 68b 0.0%
├ controllers/index.js 68b 0.0%
├ ../../node_modules/@rails/actioncable/src/adapters.js 67b 0.0%
└ ../../node_modules/timeago.js/esm/index.js 30b 0.0%
✨ Done in 0.22s.
Network transfer
Small footprint: The demo application transfers only 52 KB of data on the first visit.
Docker build time
With multi-stage building and using DockerRailsBase the build of the Docker image takes very little time. Currently, the build job requires about 1,5 minutes on GitHub Actions (see https://github.com/ledermann/templatus-hotwire/actions)
Docker image size
The Docker image is based on Alpine Linux and is optimized for minimal size (currently 117 MB uncompressed disk size). It includes just the bare minimum - no build tools like Node.js, no JS sources (just the compiled assets), no tests.
$ container-diff analyze ghcr.io/ledermann/templatus-hotwire -n
-----Size-----
Analysis for ghcr.io/ledermann/templatus-hotwire:
IMAGE DIGEST SIZE
ghcr.io/ledermann/templatus-hotwire sha256:... 117.1M
Getting started
Install for development
- Clone the repo locally:
git clone git@github.com:ledermann/templatus-hotwire.git
cd templatus-hotwire
- Install PostgreSQL, Redis, and puma-dev (if not already present). On a Mac with HomeBrew, run this to install from the
Brewfile
:
brew bundle
- Install and set up puma-dev to use HTTPS for development. Do this on macOS:
sudo puma-dev -setup
puma-dev -install
puma-dev link
# Auto-reload esbuild via puma-dev proxy
# https://github.com/puma/puma-dev#webpack-dev-server
echo 8082 > ~/.puma-dev/esbuild.templatus-hotwire
- Setup the application to install gems and NPM packages and create the database:
bin/setup
- Start the application locally:
bin/dev
Then open https://templatus-hotwire.test in your browser.
Preview components in LookBook
bin/dev
Then open https://templatus-hotwire.test/lookbook/ in your browser.
Running linters
RuboCop:
bin/rubocop
ESLint:
bin/yarn lint
Running tests locally
Ruby tests:
bin/rspec
open coverage/index.html
JavaScript unit tests:
bin/yarn test
E2E tests with Cypress:
bin/cypress open
This opens Cypress and starts Rails in development
environment, but with CYPRESS=true
, so the test
database is used. This allows code editing without class reloading and recompiling assets.
To run Cypress in headless mode:
bin/cypress run
Test deployment locally
docker network create public
docker-compose up