Render React with Phoenix

Over the holiday period this year I was lucky enough to stay in Tahoe for a week. The kids love a white Christmas. While I was there, @mjackson and his family came up for a couple days. Sledding during the day, and coding at night, what started as an impromptu Phoenix tutorial quickly became an idea between the two of us for server side rendered React with Phoenix. This post is to show what we came up with.

In pretty sort order Michael came up with react-stdio a simple javascript server that will require a file and render it as a React component over STDIO/STDOUT. It took me a little longer to come up with the goods for the Phoenix side, mostly because this was my first real foray into OTP.

Enough already. How?

Ok, so for those who are impatient, you can see a demo application at hassox/react_phx_stdio. If you want the gory details read on.

Also bear in mind that I'm a React n00b so don't expect to be wowed on that front.

The general overview

So, what we're going to do is use React in our app.js. The main component that we're going to use we'll need to pass to our react-stdio process on the server side. We'll get webpack to generate a bundle of just the component, and compile it to a server location so we can pass it to react-stdio from our view.

We're going to start up a pool of react-stdio servers and on each request, we'll pass the component bundle location and the props that the component needs to render it. We'll include the props on the page and use that to render over the top (react will notice and not render stuff).

The code

First, lets get the javascript building the server side asset. We'll hook into Phoenix's watchers to run a separate webpack in development.

Server javascript

We'll get webpack to write a component bundle to a server location to pass to react-stdio.

These are almost the same command but one uses webpack.config.js and one has webpack.server.config.js.

One thing to note: I had some trouble getting two watchers with the same key when using atoms. Phoenix seemed to collapse the two into one as a Keyword list. By using string keys this collapsing doesn't happen.

Restart your server and you should see your component.js file build.

That's most of the JS part sorted for now. We'll do the server part and then finish wiring it together to get React to hijack the pre-rendered page.

Server setup

At this point, we need to get std_json_io installed into our application.

When we restart the server now it'll fire up a bunch of fresh react-stdio servers ready to do your bidding.

Lets get something on the page

Ok so almost all the pieces are in place to get some stuff on the page. We've got our server component bundle, our supervisor running a bunch of react-stdio processes and a simple component. Next we'll add a route to spit this out to the browser.

The interesting part is the json_call!. That sends the object to the react-stdio server. The :component key is the location of the file relative to app root, and the props, well they're the props to send down. This is the current API of react-stdio. We're just following that.

Once we have the result, we'll push it to a template to render it and the props onto the page.

You shouldn't need to restart your server, it should already have refreshed.

UPDATE: I forgot to orignally put this in, but in development, you're going to want to have your react-stdio servers pick up changes to your server bundle. std_json_io has you covered on this. You can let it know to watch files and when it notices that one has changed it will kill the react-stdio servers, the supervisor will start them back up - fresh and ready to go. Drop this into your config/dev.exs (Please don't add this to any other environments. That would not be cool)

Rendering react on the server this way feels pretty good to me. We have a couple of very loosely coupled components working together to pre-render. For my first try at OTP I'm really happy with how it turned out. I love that if there's a problem with the JS and it dies, it will just start straight back up fresh.

Huge props to Michael. It was amazing to see just how fast he got react-stio up and running.