I want React server-side rendering to be easy. There aren’t a lot of React server-side rendering tools in the Rails world: React on Rails has the largest presence, but it has many bells and whistles that I’m not ready for. I could sidecar Node.js but I really don’t want another piece of infrastructure I have to manage.
I just want something simple to use and easy to get started with. So we built it. Today we’re announcing Humid 1.0!
Humid is just a few helpers for React
server-side rendering in Rails with mini_racer, a minimal and modern embedded
V8 for Ruby.
Install it
Write your renderer and wrap it with the setHumidRenderer global.
//app/assets/javascript/server_rendering.jsx
import React from 'react'
import { renderToString } from 'react-dom/server'
const Greeting = ({ name }) => <h1>Hello {name}</h1>
setHumidRenderer((json) => {
const props = JSON.parse(json)
return renderToString(<Greeting {...props} />)
})
And render it from Ruby:
require 'humid'
require 'mini_racer'
context = MiniRacer::Context.new
server_bundle = Rails.root.join("app/assets/builds/server_rendering.js")
props = JSON.generate({ name: "World" })
Humid.prepare(context, {application_path: server_bundle})
Humid.render(context, props)
# => <h1>Hello World</h1>
Best of all:
- There’s no separate Node.js process.
- It’s powered by the performance of mini_racer.
- There’s nothing that Humid does that you can’t do by yourself: it’s less than 200 lines of code.
- Instrumentation and Telemetry included.
- You can set
Humid.prepare‘s default options with an initializer.
Design
Humid is designed with two goals in mind:
- It’s for the common case where all data is gathered before rendering. Your application fetches everything needed, passes it as props, and Humid returns the rendered HTML in a single synchronous call.
- It’s a stepping stone for when you want to scale on the edge using
Cloudflare V8 isolates.
mini_racer is a bare V8 environment, if
your JS bundle works with
mini_racer, it’ll work on Cloudflare V8 isolates.
Caveats
Humid renders synchronously. It does not support streaming or async data fetching during render. Gather your data first, then pass it as props.
mini_racer is a bare V8 environment: no window, no document, no Node builtins.
Your build will need polyfills or shims. Here’s a working one for React.
mini_racer is thread safe, but not fork-safe. See guidance here for your webserver.
About thoughtbot
We've been helping engineering teams deliver exceptional products for over 20 years. Our designers, developers, and product managers work closely with teams to solve your toughest software challenges through collaborative design and development. Learn more about us.











