---
title: How We Replaced React with Phoenix
teaser: How we replaced React with server-side rendering without anyone noticing.
tags: elixir,phoenix,javascript,web
author: Blake Williams
published_on: 2016-07-12
---

About a year and a half ago we built an internal tool for company-wide
announcements. We had originally built the back-end in Phoenix and the front-end
in React, taking advantage of [Redux] and [Phoenix channels] to deliver updates
to the browser in real-time.

[Redux]: https://github.com/reactjs/redux
[Phoenix channels]: http://www.phoenixframework.org/docs/channels

This made for a great real-time experience but it also slowed down the pace of
development and caused fewer people to contribute. About three months ago we
decided that it was time to ditch React and go back to server-side rendering.

## Why we decided to replace React

Real-time updates in the browser when other users interacted with the
application made for a great experience, but it had some additional costs.

### Cost of development

Instead of building out the feature in one place we had to build it out in
the API and the UI. This also meant that anyone who wanted to contribute had to
know React *and* Phoenix which discouraged others from trying to contribute.

### Testing

Another pain point with the React codebase was testing. Since the application
and the React client were separate, it meant that we had to make sure our fake
server responses were always up to date. In practice this wasn't a large
problem, but it did burn us a few times and reduced our confidence in the tests.

### Contributions

Finally, we wanted more people to contribute. We found that having to build out
a feature in two places is a lot more work than building it out in one and
trying to coordinate the front-end and the back-end for the feature is tedious.
This is especially true since the work on this application is done during our
[investment time].

[investment time]: https://thoughtbot.com/playbook/our-company/time#investment

## The replacement

Since we already had a namespaced API in place we were able to rewrite the pages
in Phoenix and deploy to production without affecting the existing React
front-end.  Since the app is largely <abbr title="Created Read Update
Delete">CRUD</abbr> most pages were a quick one-to-one copy of the HTML
replacing `className` with `class` and replacing `{}` blocks with `<%= %>`.

In the places we needed JavaScript, we took the tried-and-true path of
"sprinkling" on the JavaScript. The best example of this is live-updating
comments. Whenever a comment is created on the back-end we broadcast to all
users that the comment was created. Instead of sending JSON, we created a
`live-html` channel where we broadcast HTML updates to users. Here's the
JavaScript code straight from the application.

```javascript
import socket from './socket'

const channel = socket.channel('live-html', {})

channel.join()
  .receive('ok', function(resp) { console.log('Joined successfully', resp) })
  .receive('error', function(resp) { console.log('Unable to join', resp) })

channel.on('new-comment', payload => {
  $(`[data-announcement-id='${payload.announcement_id}'] .comments-list`)
    .append(payload.comment_html)
})
```

That's a surprisingly small amount of JavaScript that powers a huge piece of
functionality in our application. This strategy of generating some HTML on the
server and broadcasting it to clients is much simpler than writing your entire
front-end in JavaScript for the same functionality.

We also added [Turbolinks] to the app which makes page transitions nearly
seamless and let us keep that single-page app feel.

[Turbolinks]: https://github.com/turbolinks/turbolinks

## The results

Overall the migration was relatively painless. We ended up having more people
contribute to the project in a few months than we previously had in a year with
the React front-end. The tests are much easier to write while also being much more
reliable since we didn't have to rely on the payload the back-end sends matching
up with the payload we used in tests.

Although a lot of people in the company knew the migration was happening we
didn't tell anyone when we pushed it to production. Not a single person
mentioned seeing a difference or knew that the application they were using was
no longer powered by React. This was because the time to load pages was greatly
reduced thanks to Phoenix's speed and not having to bootstrap a large amount of
data on the front-end via React.

## Lessons learned

In the end we realized and proved to ourselves that we can write Phoenix
server-rendered applications that are just as great as front-end
framework-powered single page applications. Not only is the end product just as
great &mdash; we can write features faster, have more confidence in our tests,
and more easily have other developers contribute to the application. Altogether
I think this was a huge win.

What projects have you removed front-end frameworks from recently?
