Salvia πΏ
The Future of Rails View Layer
Salvia is a next-generation Server-Side Rendering (SSR) engine designed to replace ERB with JSX/TSX in Ruby on Rails. It brings the Islands Architecture and True HTML First philosophy to the Rails ecosystem.
Vision: The Road to Sage
Salvia is the core engine for a future framework called Sage (inspired by Express, Hono, and Oak). While Sage will be a complete standalone framework, Salvia is available today as a drop-in replacement for the View layer in Ruby on Rails.
Features
- ποΈ Islands Architecture: Render interactive components (Preact/React) only where needed. Zero JS for static content.
- π True HTML First: Replace
app/views/**/*.erbwithapp/pages/**/*.tsx. - β‘ JIT Compilation: No build steps during development. Just run
rails s. - π Rails Native: Seamless integration with Controllers, Routes, and Models.
- π¦ Deno Powered: Uses Deno for lightning-fast TypeScript compilation and formatting.
Requirements
- Ruby 3.1+
- Rails 7.0+ (Recommended)
- Deno 1.30+ (Required for JIT compilation and tooling)
Installation
1. Install Deno
Salvia requires Deno. Follow the official installation guide.
# macOS / Linux
$ curl -fsSL https://deno.land/x/install/install.sh | sh2. Add Gem
Add this line to your Rails application's Gemfile:
gem 'salvia'And then execute:
$ bundle installGetting Started
1. Setup Salvia
Run the interactive installer to set up Salvia for your Rails project:
$ bundle exec salvia installThis command will:
- Create the
salvia/directory structure. - Generate
deno.json(Single Source of Truth for dependencies). - Cache Deno dependencies to ensure fast startup.
- Configure Rails to automatically include
Salvia::Helpers(providing thessrmethod).
Directory Structure
salvia/
βββ app/
β βββ components/ # Shared UI components (Buttons, Cards)
β βββ islands/ # Interactive components (Hydrated on client)
β βββ pages/ # Server Components (SSR only, 0kb JS to client)
βββ deno.json # Dependency management (Import Map)
2. Create a Page (Server Component)
Delete app/views/home/index.html.erb and create salvia/app/pages/home/Index.tsx:
import { h } from 'preact';
export default function Home({ title }) {
return (
<div class="p-10">
<h1 class="text-3xl font-bold">{title}</h1>
<p>This is rendered on the server with 0kb JavaScript sent to the client.</p>
</div>
);
}3. Render in Controller
In your Rails controller:
class HomeController < ApplicationController
def index
# Renders salvia/app/pages/home/Index.tsx
render html: ssr("home/Index", title: "Hello Salvia")
end
end4. Add Interactivity (Islands)
Create an interactive component in salvia/app/islands/Counter.tsx:
import { h } from 'preact';
import { useState } from 'preact/hooks';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)} class="btn">
Count: {count}
</button>
);
}Use it in your Page:
import Counter from '../../islands/Counter.tsx';
export default function Home() {
return (
<div>
<h1>Interactive Island</h1>
<Counter />
</div>
);
}5. Turbo Drive (Optional)
Salvia works seamlessly with Turbo Drive for SPA-like navigation.
Add Turbo to your layout file (e.g., salvia/app/pages/layouts/Main.tsx):
<head>
{/* ... */}
<script type="module">
import * as Turbo from "@hotwired/turbo";
Turbo.start();
</script>
</head>Since dependencies are managed in deno.json, you don't need to write full URLs.
Core Concepts: Pages vs Islands
Understanding the separation of concerns is crucial for "True HTML First" development.
| Feature | Pages (Server Components) | Islands (Client Components) |
|---|---|---|
| Path | salvia/app/pages/ |
salvia/app/islands/ |
| Environment | Server (Ruby/QuickJS) | Client (Browser) |
| Interactivity | β Static HTML | β Interactive (Event Listeners) |
| State | β Stateless | β Stateful (Signals/Hooks) |
| Browser APIs | β No (window, document are mocked) |
β Yes |
| Usage | Layouts, Initial Data Fetching | Forms, Modals, Dynamic UI |
Documentation
-
English:
- Wisdom for Salvia: Deep dive into the architecture, directory structure, and "True HTML First" philosophy.
- Reference Guide: Comprehensive guide on usage, API, and configuration.
- Architecture: Internal design of the gem.
-
Japanese (ζ₯ζ¬θͺ):
- README: ζ₯ζ¬θͺηREADMEγ
Framework Support
Salvia is primarily designed for Ruby on Rails to pave the way for the Sage framework.
- Ruby on Rails: First-class support.
Zero Config Architecture
Salvia v0.2.0 adopts a Zero Config philosophy.
-
deno.jsonis SSOT: It manages dependencies for both Server (SSR) and Client (Browser). -
Auto Import Map:
npm:specifiers indeno.jsonare automatically converted toesm.shURLs for the browser. -
No Build Config:
build.tsandsidecar.tsare managed internally, but you can extend globals viasalvia.globalsindeno.json.
Production & CI
In production environments (e.g., Docker, Heroku, Render):
- Deno is required: Ensure Deno is installed in your build/runtime environment.
-
Build Step: Run
bundle exec salvia buildduring deployment.- This bundles Islands, generates Import Maps, and builds Tailwind CSS.
- It generates hashed filenames for cache busting.
-
Note: While Salvia uses JIT compilation in development for a "No Build" experience,
salvia buildpre-compiles assets for production to ensure zero runtime compilation overhead.
License
The gem is available as open source under the terms of the MIT License.